OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 12 to Rev 13
    Reverse comparison

Rev 12 → Rev 13

/zipcpu/trunk/sw/zasm/test.S
8,8 → 8,8
; the CPU. As a disorganized test, it doesn't prove anything
; beyond the generic operation of the CPU.
;
; Status: As of July, 2015, the assembler isn't sophisticated enough
; to handle the address resolution needed to assemble this file.
; Status: As of August, 2015, this file assembles, builds, and passes
; all of its tests in the Verilator simulator.
;
; Creator: Dan Gisselquist, Ph.D.
; Gisselquist Tecnology, LLC
34,9 → 34,135
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
sys.bus equ 0xc0000000
sys.breaken equ 0x080
sys.step equ 0x040
sys.gie equ 0x020
sys.sleep equ 0x010
sys.ccv equ 0x008
sys.ccn equ 0x004
sys.ccc equ 0x002
sys.ccz equ 0x001
sys.bu.pic equ 0x000
sys.bus.wdt equ 0x001
sys.bus.cache equ 0x002
sys.bus.ctrpic equ 0x003
sys.bus.tma equ 0x004
sys.bus.tmb equ 0x005
sys.bus.tmc equ 0x006
sys.bus.jiffies equ 0x007
sys.bus.mtask equ 0x008
sys.bus.mpstl equ 0x009
sys.bus.mastl equ 0x00a
sys.bus.mstl equ 0x00b
sys.bus.utask equ 0x00c
sys.bus.upstl equ 0x00d
sys.bus.uastl equ 0x00e
sys.bus.ustl equ 0x00f
#define DO_TEST_ASSEMBLER
test:
#ifdef DO_TEST_ASSEMBLER
; We start out by testing our assembler. We give it some instructions, which
; are then manually checked by disassembling/dumping the result and making
; certain they match. This is not an automated test, but it is an important
; one.
noop
bra continue_test_with_testable_instructions
break
wait
busy
rtu
continue_test_with_testable_instructions:
; Now, let's place the assembler into a known state
clr r0
mov r0,r1
clr r1
clr r2
clr r3
clr r4
clr r5
clr r6
clr r7
clr r9
clr r10
clr r11
clr r12
clr r13
; Don't clear the CC register
; Don't clear the SP register
; And repeat for the user registers
mov R0,uR0
mov R0,uR1
mov R0,uR2
mov R0,uR3
mov R0,uR4
mov R0,uR5
mov R0,uR6
mov R0,uR7
mov R0,uR8
mov R0,uR9
mov R0,uR10
mov R0,uR11
mov R0,uR12
mov R0,uR13
mov R0,uCC
; Don't clear the user PC register
; Now, let's try loading some constants into registers
dead_beef equ 0xdeadbeef
ldi 0x0dead,r5
ldi 0x0beef,r6
ldi 0xdeadbeef,r7
ldihi 0xdead, r8
ldilo 0xbeef, r8
ldi dead_beef,r9
cmp r5,r6
bz test_failure
cmp r7,r8
bnz test_failure
ldi $deadbeefh,r7 ; Try loading with the $[HEX]h mneumonic
cmp r7,r8
bnz test_failure
cmp r7,r9
bnz test_failure
bra skip_dead_beef
dead_beef.base:
word 0
fill 5,dead_beef
word 0
dead_beef.zero equ 0
dead_beef.values equ 1
skip_dead_beef:
lod dead_beef.base(pc),r10 ; Should load a zero here
cmp r10,r11 ; r11 should still be zero from init abv
bnz test_failure
mov dead_beef.base(pc),r10 ; Now, let's get the address
lod dead_beef.values(r10),r10 ; r10 now equals 0xdeadbeef
cmp r10,r9
bnz test_failure
; Test whether or not we can properly decode OCTAL values
clr r0 ; Re-clear our register set first
clr r1
clr r2
clr r3
clr r4
clr r5
clr r6
clr r7
clr r9
clr r10
clr r11
clr r12
clr r13
;
ldi $024o,r0
ldi $20,r1
cmp r0,r1
bnz test_failure
ldi $024,r0
cmp r0,r1
bnz test_failure
clr r0
clr r1
mov $1+r0,r2
mov $2+r0,r3
mov $22h+r0,r4
46,30 → 172,76
add r2,r0
add $32,r0
add $-33,r0
bnz test_failure
not.z r0
bge test_failure
junk_address:
clrf r0
bnz test_failure
ldi $5,r1
cmp $0+r0,r1
not.lt r0
not.ge r1
lod $-7+pc,r2
ldihi $deadh,r3
ldihi $beefh,r3
mov junk_address(pc),r2 ; Test pc-relative addressing
mov junk_address(pc),r3
cmp r2,r3
bnz test_failure
lod junk_address(pc),r5 ; Test loads with pc-relative addressing
lod junk_address(pc),r6
cmp r5,r6
bnz test_failure
; Now, let's test whether or not our LSR and carry flags work
ldi -1,r0 ; First test: shifting all the way should yield zero
lsr 32,r0
cmp 0,r0
bnz test_failure
ldi -1,r0 ; Second test: anything greater than zero should set
lsr 0,r0 ; the carry flag
bc test_failure
lsr 1,r0
tst sys.ccc,cc
bz test_failure
lsr 31,r0
tst sys.ccc,cc
bz test_failure
lsr 1,r0
bc test_failure
; Now repeat the above tests, looking to see whether or not ASR works
ldi -1,r0
asr 32,r0
cmp -1,r0
bnz test_failure
ldi -1,r0
asr 0,r0
bc test_failure
cmp -1,r0
bnz test_failure
asr 1,r0
tst sys.ccc,r14
bz test_failure
asr 30,r0
tst sys.ccc,r14
bz test_failure
#endif
 
#ifdef NOONE // Testing comments after ifdef
#else ; After else
#endif /* and after endif */
testbench:
// Let's build a software test bench.
clr r12 ; R12 will point to our peripherals
ldihi $c000h,r12
ldi $c0000000h,r12 ; Set R12 to point to our peripheral address
mov r12,ur12
mov test_start,upc
ldihi $8001,r0
ldilo $-1,r0
sto r0,$1+r12
mov test_start(pc),upc
ldi 0x8000ffff,r0 ; Clear interrupts, turn all vectors off
sto r0,(r12)
rtu
lod r12,r0
cmp $0,r0
bnz $1
mov ucc,r0
tst -256,r0
bnz test_failure
halt
// Go into an infinite loop if the trap fails
// Permanent loop instruction -- a busy halt if you will
test_failure:
busy
 
; Now for a series of tests. If the test fails, call the trap
76,77 → 248,77
; interrupt with the test number that failed. Upon completion,
; call the trap with #0.
 
; Now for a series of tests. If the test fails, call the trap
; interrupt with the test number that failed. Upon completion,
; call the trap with #0.
 
; Test LDI to PC
; Some data registers
.dat __here__+5
test_data:
.dat __here__+0x0100000+5
test_start:
ldi $2,r11
lod $-3+pc,pc
ldi $0x0100,r11
lod test_data+pc,pc
clr r11
noop
cmp $0,r11
sto.z r11,(r12)
trap.z r11
add $1,r0
add $1,r0
 
// Let's test whether overflow works
ldi $3,r11
ldi $0x0200,r11
ldi $-1,r0
lsr $1,r0
add $1,r0
bv $1
sto r11,(r12)
bv first_overflow_passes
trap r11
first_overflow_passes:
// Overflow set from subtraction
ldi $4,r11
ldi $0x0300,r11
ldi $1,r0
.dat 0x5000001f ; rol $31,r0
rol $31,r0 ; rol $31,r0
sub $1,r0
bv $1
sto r11,(r12)
bv subtraction_overflow_passes
trap r11
subtraction_overflow_passes:
// Overflow set from LSR
ldi $5,r11
ldi $0x0400,r11
ldi $1,r0
.dat 0x5000001f ; rol $31,r0
rol $31,r0 ; rol $31,r0
lsr $1,r0
bv $1
sto r11,(r12)
bv lsr_overflow_passes
trap r11
lsr_overflow_passes:
// Overflow set from LSL
ldi $6,r11
ldi $0x0500,r11
ldi $1,r0
.dat 0x5000001e
rol $30,r0
lsl $1,r0
bv $1
sto r11,(r12)
 
bv lsl_overflow_passes
trap r11
lsl_overflow_passes:
// Overflow set from LSL, negative to positive
ldi $7,r11
ldi $0x0600,r11
ldi $1,r0
.dat 0x5000001f; // E: ROL $30,R0
rol $31,r0
lsl $1,r0
bv $1
sto r11,(r12)
 
bv second_lsl_overflow_passes
trap r11
second_lsl_overflow_passes:
// Test carry
ldi $0x010,r11
ldi $0x0700,r11
ldi $-1,r0
add $1,r0
tst $2,cc
sto.z r11,(r12)
trap.z r11
// and carry from subtraction
ldi $17,r11
ldi $0x0800,r11
sub $1,r0
tst $2,cc
sto.z r11,(r12)
trap.z r11
 
// Let's try a loop: for i=0; i<5; i++)
// We'll use R0=i, Immediates for 5
ldi $0x0800,r11
clr r0
for_loop:
ldi $18,r11
clr r0
noop
add $1,r0
cmp $5,r0
158,8 → 330,8
// R0 = 5; (from before)
// do {
// } while (R0 > 0);
ldi $0x0900,r11
bgt_loop:
ldi $19,r11
noop
sub $1,r0
bgt bgt_loop
168,7 → 340,7
// R1 = 5; // Need to do this explicitly
// do {
// } while(R1 >= 0);
ldi $20,r00
ldi $20,r0
ldi $5,r1
bge_loop:
noop
180,31 → 352,31
// R0 = 5; (from before)
// do {
// } while (R0 > 0);
ldi $21,r11
bra $1
ldi $0x0a00,r11
bra mem_loop_test
loop_var:
.dat 0
mem_loop_test:
mov loop_var(pc),r1
ldi $5,r0
clr r2
sto r0,(r1)
mem_loop:
mov $-2+pc,r1
clr r2
ldi $5,r0
sto r1,(r0)
add $1,r2
add $14,r0
lod (r1),r0
sub $1,r0
bgt $-6
sto r0,(r1)
bgt mem_loop
cmp $5,r2
sto.ne r11,(r12)
trap.ne r11
 
// Return success / Test the trap interrupt
clr r11
sto r11,(r12)
trap r11
noop
noop
 
// Go into an infinite loop if the trap fails
// Permanent loop instruction -- a busy halt if you will
busy
 
// And, in case we miss a halt ...
/zipcpu/trunk/sw/zasm/zasm.y
0,0 → 1,508
/*******************************************************************************
**
** Filename: zasm.y
**
** Project: Zip CPU -- a small, lightweight, RISC CPU core
**
** Purpose: The parser for the Zip Assembler. This is actually not just
** the parser, but the main program as well.
**
** Creator: Dan Gisselquist, Ph.D.
** Gisselquist Tecnology, LLC
**
********************************************************************************
**
** Copyright (C) 2015, Gisselquist Technology, LLC
**
** This program is free software (firmware): you can redistribute it and/or
** modify it under the terms of the GNU General Public License as published
** by the Free Software Foundation, either version 3 of the License, or (at
** your option) any later version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
** for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program. (It's in the $(ROOT)/doc directory, run make with no
** target there if the PDF file isn't present.) If not, see
** <http://www.gnu.org/licenses/> for a copy.
**
** License: GPL, v3, as defined and found on www.gnu.org,
** http://www.gnu.org/licenses/gpl.html
**
**
*******************************************************************************/
 
%{
#include <stdio.h>
#include <string.h>
#include "asmdata.h"
 
extern "C" int yylex(void);
extern "C" int yyparse(void);
// extern "C" FILE *yyin;
void yyerror(const char *);
unsigned int global_parser_pc;
char *master_input_filename = NULL;
extern int yylineno;
char *linecp = NULL; // A copy of the input line
%}
 
%token COMMA EQU PLUS MINUS TIMES HERE DOLLAR COLON
%token BOOLEANOR BITWISEOR BOOLEANAND BITWISEAND BITWISEXOR DOT
%token WORD FILL
%token LOADOP STOROP LDIOP
%token BAREOP BRANCHOP COND DUALOP IDENTIFIER INT LDHLOP REG SINGLOP
 
%union {
ZPARSER::ZIPREG u_reg;
ZPARSER::ZIPCOND u_cond;
int u_ival;
LEXOPCODE u_op;
char *u_id;
ASMLINE *u_ln;
AST *u_ast;
}
 
%type <u_reg> REG
%type <u_cond> COND opcond
%type <u_ival> INT
%type <u_id> IDENTIFIER
%type <u_op> BAREOP SINGLOP DUALOP BRANCHOP LDHLOP
%type <u_ln> unlabeledline instruction wordlist fillist opb
%type <u_ln> bareop singlop dualop loadop storop line
%type <u_ast> expr value multident
 
%% /* The grammar follows */
 
input:
%empty
| input line { if ($2) {objcode += $2; global_parser_pc += $2->nlines(); if ($2->isdefined()) delete $2; } }
;
 
line:
'\n' { $$ = NULL; }
| unlabeledline '\n' { $$ = $1; }
| multident COLON unlabeledline '\n' {
if ($1->m_node_type == 'I') {
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
else
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
delete $1;
}
$$ = $3;
}
| multident COLON '\n' {
if ($1->m_node_type == 'I') {
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
else
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
delete $1;
}
$$ = new VLINE();
}
| multident EQU expr '\n' {
if ($1->m_node_type == 'I') {
stb_define(((AST_IDENTIFIER *)$1)->m_id, $3);
delete $1;
}
$$ = new VLINE();
}
;
 
unlabeledline:
instruction { $$ = $1; }
| WORD wordlist { $$ = $2; }
| FILL fillist { $$ = $2; }
;
 
wordlist:
expr {
if ($1->isdefined())
$$ = new DLINE($1->eval());
else {
$$ = new VLINE();
yyerror("ERROR: word list undefined");
}}
| expr COMMA wordlist {
if ($1->isdefined())
$$ = new DLINE($1->eval());
else {
$$ = new VLINE();
yyerror("ERROR: word list undefined\n");
}}
;
 
fillist:
expr COMMA expr {
if (($1->isdefined())&&($3->isdefined())) {
int ntimes = $1->eval(),
val = $3->eval();
LLINE *ln = new LLINE();
for(int i=0; i<ntimes; i++)
ln->addline(new DLINE(val));
$$ = ln;
} else {
yyerror("Fill list undefined\n");
$$ = new VLINE();
}
}
;
 
instruction:
dualop opb COMMA REG {
$$ = $1;
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
((TLINE*)$1)->m_opa = $4;
if ($1->isdefined()) {
$$ = ((TLINE*)$1)->eval();
delete $1;
delete $2;
}
}
| dualop opb COMMA multident {
char buf[256];
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
yyerror(buf);
$$ = new VLINE();
delete $1;
delete $2;
delete $4;
}
| singlop opb {
$$ = $1;
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
if ($1->isdefined()) {
$$ = ((TLINE *)$1)->eval();
delete $1;
}
}
| bareop { $$ = $1; }
| LDHLOP opcond expr COMMA REG {
TLINE *tln = new TLINE;
tln->m_opcode = $1;
tln->m_cond = $2;
tln->m_imm = $3;
tln->m_opa = $5;
 
if (tln->isdefined()) {
$$ = tln->eval();
delete tln;
} else
$$ = tln;
}
| LDHLOP opcond expr COMMA multident {
char buf[256];
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$5)->m_id.c_str());
yyerror(buf);
$$ = new VLINE();
delete $3;
delete $5;
}
| LDIOP expr COMMA REG {
TLINE *tln = new TLINE;
tln->m_opcode = OP_LDI;
tln->m_cond = ZPARSER::ZIPC_ALWAYS;
tln->m_imm = $2;
tln->m_opa = $4;
 
if (tln->isdefined()) {
$$ = tln->eval();
delete tln;
} else
$$ = tln;
}
| LDIOP expr COMMA multident {
char buf[256];
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
yyerror(buf);
$$ = new VLINE();
delete $2;
delete $4;
}
| BRANCHOP expr {
TLINE *tln = new TLINE;
tln->m_opcode = $1;
tln->m_imm = $2;
 
if (tln->isdefined()) {
$$ = tln->eval();
delete tln;
} else
$$ = tln;
}
| loadop opb COMMA REG {
TLINE *tln = new TLINE;
((TLINE*)$2)->m_opcode = OP_LOD;
((TLINE*)$2)->m_cond = ((TLINE*)$1)->m_cond;
((TLINE*)$2)->m_opa = $4;
 
delete $1;
 
if (((TLINE *)$2)->isdefined()) {
$$ = ((TLINE *)$2)->eval();
delete $2;
} else
$$ = $2;
}
| loadop opb COMMA multident {
char buf[256];
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
yyerror(buf);
$$ = new VLINE();
delete $1;
delete $2;
delete $4;
}
| storop REG COMMA opb {
TLINE *tln = new TLINE;
tln->m_opcode = OP_STO;
tln->m_cond = ((TLINE*)$1)->m_cond;
tln->m_imm = ((TLINE*)$4)->m_imm;
tln->m_opb = ((TLINE*)$4)->m_opb;
tln->m_opa = $2;
 
delete $1;
 
if (tln->isdefined()) {
$$ = tln->eval();
delete tln;
} else
$$ = tln;
}
| storop multident COMMA opb {
char buf[256];
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$2)->m_id.c_str());
yyerror(buf);
$$ = new VLINE();
delete $1;
delete $2;
delete $4;
}
;
 
dualop: DUALOP opcond {
TLINE *tln = new TLINE();
tln->m_opcode = $1;
tln->m_cond = $2;
$$ = tln;
}
;
 
singlop: SINGLOP opcond {
TLINE *tln = new TLINE();
tln->m_opcode = $1;
tln->m_cond = $2;
$$ = tln;
}
;
 
storop: STOROP opcond {
TLINE *tln = new TLINE();
tln->m_opcode = OP_STO;
tln->m_cond = $2;
$$ = tln;
}
;
 
loadop: LOADOP opcond {
TLINE *tln = new TLINE();
tln->m_opcode = OP_LOD;
tln->m_cond = $2;
$$ = tln;
}
;
 
bareop: BAREOP opcond {
TLINE *tln = new TLINE();
tln->m_opcode = $1;
tln->m_cond = $2;
$$ = tln;
}
;
 
opcond:
COND { $$ = $1; }
| %empty { $$ = ZPARSER::ZIPC_ALWAYS; }
;
 
opb:
expr {
TLINE *tln = new TLINE();
tln->m_imm = $1;
$$ = tln;
}
| expr PLUS REG {
TLINE *tln = new TLINE();
tln->m_imm = $1;
tln->m_opb = $3;
$$ = tln;
}
| expr '(' REG ')' {
TLINE *tln = new TLINE();
tln->m_imm = $1;
tln->m_opb = $3;
$$ = tln;
}
| '(' REG ')' {
TLINE *tln = new TLINE();
tln->m_imm = new AST_NUMBER(0);
tln->m_opb = $2;
$$ = tln;
}
| REG {
TLINE *tln = new TLINE();
tln->m_imm = new AST_NUMBER(0);
tln->m_opb = $1;
$$ = tln;
}
;
 
expr:
value { $$ = $1; }
| MINUS value { $$ = new AST_BRANCH('-',new AST_NUMBER(0), $2); }
| expr PLUS value { $$ = new AST_BRANCH('+',$1,$3); }
| expr MINUS value { $$ = new AST_BRANCH('-',$1,$3); }
| expr TIMES value { $$ = new AST_BRANCH('*',$1,$3); }
| expr BOOLEANOR value { $$ = new AST_BRANCH('o',$1,$3); }
| expr BITWISEOR value { $$ = new AST_BRANCH('|',$1,$3); }
| expr BOOLEANAND value { $$ = new AST_BRANCH('a',$1,$3); }
| expr BITWISEAND value { $$ = new AST_BRANCH('&',$1,$3); }
| expr BITWISEXOR value { $$ = new AST_BRANCH('^',$1,$3); }
| '(' expr ')' { $$ = $2; }
;
/* expr OR (|) value */
/* expr XOR (^) value */
/* expr AND (&) value */
 
value:
INT { $$ = new AST_NUMBER($1); }
| multident { $$ = $1; }
| HERE { $$ = new AST_NUMBER(global_parser_pc); }
;
 
multident:
IDENTIFIER { $$ = new AST_IDENTIFIER($1); delete $1; }
| multident DOT IDENTIFIER { $$ = new AST_IDENTIFIER($1,$3); delete $3; }
;
%%
 
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <assert.h>
 
OBJFILE objcode;
 
void yyerror(const char *str) {
fprintf(stderr, "%s:%d: ERROR: %s\n", master_input_filename, yylineno, str);
if (linecp) fprintf(stderr, "Offending line was: %s\n", linecp);
}
 
FILE *run_preprocessor(const char *zname = NULL) {
int pipefd[2];
int pid;
 
if (pipe(pipefd)!=0) {
fprintf(stderr, "PIPE FAILED!\n");
perror("O/S Err:");
exit(-2);
} if ((zname)&&(access(zname, R_OK)!=0)) { // if !zname, then use stdin
fprintf(stderr, "Cannot open %s\n", zname);
perror("O/S Err:");
exit(-2);
}
 
 
if (0 == (pid = fork())) {
int fdin, fdout;
 
// Child process -- run the preprocessor
if (zname) {
fdin = open(zname, O_RDONLY);
close(STDIN_FILENO);
dup2(fdin, STDIN_FILENO);
} // else use stdin, already set up
 
close(pipefd[0]);
 
fdout = pipefd[1];
close(STDOUT_FILENO);
dup2(fdout, STDOUT_FILENO);
 
// This call should never return
execlp("./zpp", "zpp", NULL);
 
fprintf(stderr, "Could not start pre-processor!\n");
perror("O/S Err:");
 
exit(-5);
}
 
close(pipefd[1]);
return fdopen(pipefd[0], "r");
}
 
int main(int argc, char **argv) {
int skp = 0;
const char *zout_fname = NULL;
master_input_filename = NULL;
 
skp=1;
for(int argn=0; argn+skp<argc; argn++) {
if (argv[argn+skp][0] == '-') {
if (argv[argn+skp][1] == 'o') {
if (zout_fname)
free((void *)zout_fname);
zout_fname = strdup(argv[argn+skp+1]);
skp++;
}
 
skp++;
} argv[argn] = argv[argn+skp];
} argc -= skp;
 
if (!zout_fname)
zout_fname = "z.out";
 
objcode.open(zout_fname);
 
master_input_filename = NULL;
 
if (argc > 0) {
for(int argn=0; argn<argc; argn++) {
extern FILE *yyin;
extern void yyrestart(FILE *);
FILE *tst;
 
create_new_context();
if (master_input_filename)
free(master_input_filename);
master_input_filename = strdup(argv[argn]);
yyrestart(run_preprocessor(master_input_filename));
yylineno = 1;
yyparse();
}
} else { // Run from Stdin
extern FILE *yyin;
extern void yyrestart(FILE *);
 
create_new_context();
master_input_filename = strdup("(stdin)");
yyin = run_preprocessor(NULL);
yyrestart(yyin);
yyparse();
}
 
if (!objcode.reduce())
fprintf(stderr, "Not all symbols defined!\n");
}
 
 
/zipcpu/trunk/sw/zasm/asmdata.cpp
0,0 → 1,708
////////////////////////////////////////////////////////////////////////////////
//
// Filename: asmdata.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: Like asmdata.h, this contains necessary data structures for the
// assembler. Specifically, in C/C++ fashion, this contains most
// of the code for actually building such structures.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
 
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "asmdata.h"
 
extern void yyerror(const char *str);
 
unsigned int ILINE::eval(const int lno) {
return (lno==0)?m_in:DEFAULT_LINE;
}
 
unsigned int VLINE::eval(const int lno) {
return DEFAULT_LINE;
}
 
unsigned int DLINE::eval(const int lno) {
return (lno==0)?m_data:DEFAULT_LINE;
}
 
void LLINE::addline(ASMLINE *line) {
if (m_lines != NULL) {
ASMLINE **nwlines = new ASMLINE *[m_nlines+1];
for(int i=0; i<m_nlines; i++)
nwlines[i] = m_lines[i];
delete[] m_lines;
nwlines[m_nlines++] = line;
 
m_lines = nwlines;
} else {
m_lines = new ASMLINE *[1];
m_lines[m_nlines++] = line;
}
};
 
bool LLINE::isdefined(void) {
for(int i=0; i<m_nlines; i++)
if (!m_lines[i]->isdefined())
return false;
return true;
};
 
LLINE::~LLINE(void) {
for(int i=0; i<m_nlines; i++)
delete m_lines[i];
delete m_lines;
}
 
unsigned int LLINE::eval(const int lno) {
return (lno < m_nlines)?m_lines[lno]->eval(0) : DEFAULT_LINE;
}
 
// int m_op; // An operator
// AST *m_left, *m_right;
 
int AST_BRANCH::eval(void) {
int lft = m_left->eval(), rht = m_right->eval();
 
switch(m_op) {
case '+': return lft + rht;
case '-': return lft - rht;
case '*': return lft * rht;
case '/': return lft / rht;
case '%': return lft % rht;
case '^': return lft ^ rht;
case '|': return lft | rht;
case '&': return lft & rht;
case '~': return ~lft;
default: yyerror("Unknown operation"); return lft;
}
} void AST_BRANCH::reduce(void) {
if ((m_left)&&(m_left->m_node_type != 'N')&&(m_left->isdefined())) {
int val = m_left->eval();
delete m_left;
m_left = new AST_NUMBER(val);
} else
m_left->reduce();
if ((m_right)&&(m_right->m_node_type != 'N')&&(m_right->isdefined())) {
int val = m_right->eval();
delete m_right;
m_right = new AST_NUMBER(val);
} else
m_right->reduce();
}
 
AST_IDENTIFIER::AST_IDENTIFIER(AST *ida, const char *idb) {
m_node_type = 'I';
m_id = ((AST_IDENTIFIER*)ida)->m_id + "." + std::string(idb);
delete ida;
}
 
bool AST_IDENTIFIER::isdefined(void) {
bool answer = stb_isdefined(m_id);
return answer;
} int AST_IDENTIFIER::eval(void) {
return stb_value(m_id);
} void AST_IDENTIFIER::reduce(void) {}
 
bool AST_LABEL::isdefined(void) {
bool answer = stb_isdefined(m_label);
return answer;
} int AST_LABEL::eval(void) {
return stb_value(m_label);
} void AST_LABEL::reduce(void) {}
 
 
int AST_NUMBER::eval(void) {
return m_val;
} void AST_NUMBER::reduce(void) {}
 
void OBJFILE::open(const char *fname) {
if ((m_fp != NULL)||(m_pc != 0l)) {
fprintf(stderr, "Error: Can only change file names at startup\n");
exit(-2);
}
m_fp = fopen(fname, "w");
if (m_fp == NULL) {
fprintf(stderr, "Cannot open %s for writing\n", fname);
perror("O/S Err:");
m_fp = fopen("/dev/null","w");
}
}
 
void OBJFILE::operator+=(ASMLINE *ln) {
unsigned int buf[1];
int nlines = ln->nlines();
 
if (!ln->isdefined()) {
// fprintf(stderr, "%08x: Adding undefined line:\n", m_pc);
// ((TLINE *)ln)->dump(stderr);
m_tbl.insert(m_tbl.end(), SAVED_ASMLINE(m_pc,ln));
/*
} else {
fprintf(stderr, "%08x: Adding to file:\n", m_pc);
((TLINE *)ln)->dump(stderr);
*/
}
for(int i=0; i<nlines; i++) {
buf[0] = ln->eval(i);
if (m_fp) fwrite(buf, sizeof(ZIPI), 1, m_fp);
m_pc++;
}
}
 
bool OBJFILE::reduce(void) {
SVDTBL::iterator i;
bool all_reduced = true;
 
// printf("Checking for reductions\n");
unsigned int tmp = m_pc;
for(i=m_tbl.begin(); i != m_tbl.end(); i++) {
// printf("LINE %08x\n", i->m_pc);
ASMLINE *ln = i->m_ln;
m_pc = i->m_pc;
if (ln->isdefined()) {
// printf("PC = 0x%08x reduces\n", i->m_pc);
fseek(m_fp, sizeof(ZIPI)*i->m_pc, SEEK_SET);
for(int k=0; k< ln->nlines(); k++) {
ZIPI buf[1];
m_pc = i->m_pc+k;
buf[0] = ln->eval(k);
// printf("\t0x%08x -> %08x\n", i->m_pc+k,
// buf[0]);
fwrite(buf, sizeof(ZIPI), 1, m_fp);
}
} else {
fprintf(stderr, "PC = 0x%08x isn\'t ready yet\n", i->m_pc);
i->m_ln->dump(stderr);
all_reduced = false;
}
} m_pc = tmp;
return all_reduced;
}
 
bool fitsin(const int v, const int b) {
if (v>0)
return (v < (1<<(b-1)));
else
return (-v <= (1<<b));
}
 
#define BLD_DUALOP(OP) \
if (m_opa == zp.ZIP_Rnone) \
yyerror("Err: Dual Ops need a result register"); \
if (m_opb != zp.ZIP_Rnone) { \
if(!fitsin(imm, 16)) \
yyerror("16-bit: Immediate out of range"); \
in = zp.OP(m_cond,imm,m_opb,m_opa); \
} else { \
if(!fitsin(imm, 20)) \
yyerror("20-bit: Immediate out of range"); \
in = zp.OP(m_cond,imm,m_opa); \
}
 
#define BLD_BRANCH(OP,CND) \
if (fitsin(offset, 16)) \
in = zp.OP(offset); \
else if (fitsin(offset, 20)) \
in = zp.op_add(zp.CND, offset, zp.ZIP_PC); \
else { in = zp.OP(offset); yyerror("LONG JUMP NOT SUPPORTED"); }
 
ASMLINE *TLINE::eval(void) {
ZIPI in;
ZPARSER zp;
int offset = 0, imm = 0;
 
if (m_opcode != OP_MOV) {
if ( ((m_opa!=zp.ZIP_Rnone)&&(m_opa > zp.ZIP_PC))
|| ((m_opb!=zp.ZIP_Rnone)&&(m_opb > zp.ZIP_PC)) )
yyerror("Only move instructions can reference user regs");
}
 
// Offset used in jumps
if (m_imm) {
imm = m_imm->eval();
offset = imm-objcode.pc()-1;
 
if (m_opb == zp.ZIP_PC)
imm = offset;
}
 
switch(m_opcode) {
case OP_CMP:
BLD_DUALOP(op_cmp)
break;
case OP_TST:
BLD_DUALOP(op_tst)
break;
case OP_MOV:
if ((m_opa == zp.ZIP_Rnone)||(m_opb == zp.ZIP_Rnone)) {
yyerror("Moves can only occurr between registers");
fprintf(stderr, "m_opa = %d, m_opb = %d\n", m_opa, m_opb);
fprintf(stderr, "m_imm = %d\n", imm);
} else if (!fitsin(imm, 16))
yyerror("Immediate overflow on move");
in = zp.op_mov(m_cond, imm, m_opb, m_opa);
break;
case OP_LDIHI:
if ((imm & (-1<<16))!=0)
yyerror("16-bit Immediate out of range");
if (m_opb != zp.ZIP_Rnone)
yyerror("LDIHI cannot accept OP-B registers");
if (m_opa == zp.ZIP_Rnone)
yyerror("LDIHI needs a register result");
in = zp.op_ldihi(m_cond, imm, m_opa);
break;
case OP_LDILO:
if ((imm & (-1<<16))!=0)
yyerror("16-bit Immediate out of range");
if (m_opb != zp.ZIP_Rnone)
yyerror("LDIHI cannot accept OP-B registers");
if (m_opa == zp.ZIP_Rnone)
yyerror("LDIHI needs a register result");
if ((imm & (-1<<16))!=0)
yyerror("16-bit Immediate out of range");
in = zp.op_ldilo(m_cond, imm, m_opa);
break;
case OP_MPY:
in = zp.op_mpy(m_cond, imm, m_opb, m_opa);
break;
case OP_ROL:
if (m_opa == zp.ZIP_Rnone)
yyerror("ROL needs a register result");
if (m_opb != zp.ZIP_Rnone)
in = zp.op_rol(m_cond, imm, m_opb, m_opa);
else
in = zp.op_rol(m_cond, imm, m_opa);
break;
case OP_SUB:
BLD_DUALOP(op_sub)
break;
case OP_AND:
BLD_DUALOP(op_and)
break;
case OP_ADD:
BLD_DUALOP(op_add)
break;
case OP_OR:
BLD_DUALOP(op_or)
break;
case OP_XOR:
BLD_DUALOP(op_xor)
break;
case OP_LSL:
BLD_DUALOP(op_lsl)
break;
case OP_ASR:
BLD_DUALOP(op_asr)
break;
case OP_LSR:
BLD_DUALOP(op_lsr)
break;
case OP_LOD:
if (m_opb != zp.ZIP_Rnone)
in = zp.op_lod(m_cond, imm, m_opb, m_opa);
else
in = zp.op_lod(m_cond, imm, m_opa);
break;
case OP_STO:
if (m_opb != zp.ZIP_Rnone)
in = zp.op_sto(m_cond, m_opa, imm, m_opb);
else
in = zp.op_sto(m_cond, m_opa, imm);
break;
case OP_LDI:
if ((!fitsin(imm, 24))||(m_cond != zp.ZIPC_ALWAYS)) {
if (m_opa == zp.ZIP_PC)
yyerror("Cannot LDI 32-bit addresses into PC register!");
LLINE *lln = new LLINE;
lln->addline(new ILINE(zp.op_ldihi(m_cond, (imm>>16)&0x0ffff, m_opa)));
lln->addline(new ILINE(zp.op_ldilo(m_cond, imm&0x0ffff, m_opa)));
return lln;
} else
in = zp.op_ldi(imm, m_opa);
break;
case OP_CLRF:
in = zp.op_clrf(m_cond, m_opb);
break;
case OP_NOT:
in = zp.op_not(m_cond, m_opb);
break;
case OP_JMP:
if (!fitsin(imm, 16))
yyerror("JMP: Immediate out of range");
else if (m_opb == zp.ZIP_Rnone) {
if (m_cond != zp.ZIPC_ALWAYS)
yyerror("JMP: Conditions are not allowed for absolute jumps.");
imm &= (1<<24)-1;
if (!fitsin(imm, 24))
yyerror("JMP: Absolute jump address out of range");
zp.op_ldi(imm, zp.ZIP_PC);
}
in = zp.op_mov(m_cond, imm, m_opb, zp.ZIP_PC);
case OP_BRA:
BLD_BRANCH(op_bra,ZIPC_ALWAYS)
break;
case OP_BZ:
BLD_BRANCH(op_brz,ZIPC_Z)
break;
case OP_BNZ:
BLD_BRANCH(op_bnz,ZIPC_NZ)
break;
case OP_BGE:
BLD_BRANCH(op_bge,ZIPC_GE)
break;
case OP_BGT:
BLD_BRANCH(op_bgt,ZIPC_GT)
break;
case OP_BLT:
BLD_BRANCH(op_blt,ZIPC_LT)
break;
case OP_BRC:
BLD_BRANCH(op_brc,ZIPC_C)
break;
case OP_BRV:
BLD_BRANCH(op_brv,ZIPC_V)
break;
case OP_CLR:
in = zp.op_clr(m_opb);
break;
case OP_TRAP:
if((m_opb == zp.ZIP_Rnone)&&(m_cond == zp.ZIPC_ALWAYS))
in = zp.op_ldi(imm, zp.ZIP_CC);
else if((m_opb == zp.ZIP_Rnone)&&((imm&0x0ffff)==imm))
in = zp.op_ldilo(imm, zp.ZIP_CC);
else if((m_opb != zp.ZIP_Rnone)&&(fitsin(imm, 16)))
in = zp.op_mov(m_cond, imm, m_opb, zp.ZIP_CC);
else {
yyerror("Illegal trap!");
in = zp.op_trap(m_cond, 0);
}
break;
case OP_HALT: in = zp.op_halt(m_cond); break;
case OP_RTU: in = zp.op_rtu(m_cond); break;
case OP_BUSY: in = zp.op_busy(m_cond); break;
case OP_BREAK: in = zp.op_break(); break;
case OP_NOOP: in = zp.op_noop(); break;
// OP_LJMP:
case OP_NONE:
default: { char ebuf[256]; sprintf(ebuf, "Unrecognized OP-Code, %d, NONE = %d, CLR=%d", m_opcode, OP_NONE, OP_CLR);
yyerror(ebuf);
in = zp.op_noop(); break;
}
} return new ILINE(in);
}
 
int TLINE::nlines(void) {
if ((m_opcode == OP_LDI)&&( (!(m_imm->isdefined()))
|| (m_cond != ZPARSER::ZIPC_ALWAYS)
|| (!fitsin(m_imm->eval(), 24)) )) {
return 2;
}
return 1;
}
 
unsigned int TLINE::eval(const int lno) {
if (!isdefined())
return DEFAULT_LINE;
else {
ASMLINE *ln = this->eval();
unsigned int val = ln->eval(lno);
delete ln;
return val;
}
}
 
void TLINE::dump(FILE *fp) {
if (m_state == 'V')
fprintf(fp, "Void\n");
else if (m_state != 'T')
fprintf(fp, "TLINE state != T (== %c)\n", m_state);
else {
fprintf(fp, "TLINE\n");
switch(m_opcode) {
case OP_CMP: fprintf(fp, "\tTLINE OP = CMP\n");
break;
case OP_TST: fprintf(fp, "\tTLINE OP = TST\n");
break;
case OP_MOV: fprintf(fp, "\tTLINE OP = MOV\n");
break;
case OP_LDIHI: fprintf(fp, "\tTLINE OP = LDIHI\n");
break;
case OP_LDILO: fprintf(fp, "\tTLINE OP = LDILO\n");
break;
case OP_MPY: fprintf(fp, "\tTLINE OP = MPY\n");
break;
case OP_ROL: fprintf(fp, "\tTLINE OP = ROL\n");
break;
case OP_SUB: fprintf(fp, "\tTLINE OP = SUB\n");
break;
case OP_AND: fprintf(fp, "\tTLINE OP = AND\n");
break;
case OP_ADD: fprintf(fp, "\tTLINE OP = ADD\n");
break;
case OP_OR: fprintf(fp, "\tTLINE OP = OR\n");
break;
case OP_XOR: fprintf(fp, "\tTLINE OP = XOR\n");
break;
case OP_LSL: fprintf(fp, "\tTLINE OP = LSL\n");
break;
case OP_ASR: fprintf(fp, "\tTLINE OP = ASR\n");
break;
case OP_LSR: fprintf(fp, "\tTLINE OP = LSR\n");
break;
case OP_LOD: fprintf(fp, "\tTLINE OP = LOD\n");
break;
case OP_STO: fprintf(fp, "\tTLINE OP = STO\n");
break;
case OP_LDI: fprintf(fp, "\tTLINE OP = LDI\n");
break;
case OP_CLRF: fprintf(fp, "\tTLINE OP = CLRF\n");
break;
case OP_NOT: fprintf(fp, "\tTLINE OP = NOT\n");
break;
case OP_JMP: fprintf(fp, "\tTLINE OP = JMP\n");
break;
case OP_BRA: fprintf(fp, "\tTLINE OP = BRA\n");
break;
case OP_BZ:
case OP_BNZ:
case OP_BGE:
case OP_BGT:
case OP_BLT:
case OP_BRC:
case OP_BRV:
fprintf(fp, "\tTLINE OP = BRA.C\n");
break;
case OP_CLR: fprintf(fp, "\tTLINE OP = CLR\n");
break;
case OP_TRAP: fprintf(fp, "\tTLINE OP = TRAP\n");
break;
case OP_HALT: fprintf(fp, "\tTLINE OP = HALT\n");
break;
case OP_RTU: fprintf(fp, "\tTLINE OP = RTU\n");
break;
case OP_BUSY: fprintf(fp, "\tTLINE OP = BUSY\n");
break;
case OP_BREAK: fprintf(fp, "\tTLINE OP = BREAK\n");
break;
case OP_NOOP: fprintf(fp, "\tTLINE OP = NOOP\n");
break;
// OP_LJMP:
case OP_NONE:
default:
fprintf(fp, "\tTLINE OP = (Unrecognized, %d)\n", m_opcode);
break;
}
fprintf(fp, "\tTLINE COND = %d\n", m_cond);
if (m_imm == NULL)
fprintf(fp, "\tTLINE imm = (NULL)\n");
else if (!m_imm->isdefined()) {
m_imm->reduce();
fprintf(fp, "\tTLINE imm = ");
m_imm->dump(fp);
fprintf(fp, "\n");
} else
fprintf(fp, "\tTLINE imm = %d\n", m_imm->eval());
fprintf(fp, "\tTLINE opb = %d\n", m_opb);
fprintf(fp, "\tTLINE opa = %d\n", m_opa);
}
}
 
 
// Now, for our symbol table
class SYMTABLE_ENTRY {
private:
int m_recursion_check;
 
std::string &trim(std::string &s) {
std::string::iterator ptr = s.end()-1;
 
while((ptr >= s.begin())&&(isspace(*ptr)))
*ptr-- = '\0';
if (*ptr == ':')
*ptr-- = '\0';
 
// printf("STORING: %s\n", s.c_str());
 
return s;
}
 
public:
std::string m_name;
AST *m_value;
SYMTABLE_ENTRY(const char *str) : m_recursion_check(0), m_name(str), m_value(NULL) {
trim(m_name);
} SYMTABLE_ENTRY(const char *str, AST *v) : m_recursion_check(0), m_name(str), m_value(v) {
trim(m_name);
} ~SYMTABLE_ENTRY(void) {
delete m_value;
}
 
SYMTABLE_ENTRY &operator=(AST *new_value) {
if (m_value)
delete m_value;
m_value = new_value;
}
 
bool isdefined(void) {
if (m_recursion_check > 0) {
fprintf(stderr, "RECURSION DETECTED! Symbol: %s\n",
m_name.c_str());
return false;
}
m_recursion_check = 1;
if (m_value->m_node_type != 'N')
m_value->reduce();
bool answer = m_value->isdefined();
m_recursion_check = 0;
return answer;
}
int val(void) {
if ((m_value->isdefined())&&(m_value->m_node_type != 'N')) {
int v = m_value->eval();
AST *tmp;
tmp = m_value;
m_value = new AST_NUMBER(v);
delete tmp;
} return (m_value->eval());
}
void dump(FILE *fp) { m_value->dump(fp); }
};
 
class SYMBOL_TABLE {
private:
typedef SYMTABLE_ENTRY *TBLV;
typedef std::list<TBLV> TBLT;
 
TBLT m_tbl;
 
TBLT::iterator lookup(const char *str) {
TBLT::iterator i = m_tbl.begin();
for(; (i!=m_tbl.end())&&(strcmp(str, (*i)->m_name.c_str())>0);
i++)
;
if ((i != m_tbl.end())&&(strcmp(str,(*i)->m_name.c_str())==0))
return i;
return m_tbl.end();
}
 
public:
SYMBOL_TABLE(void) {}
~SYMBOL_TABLE(void) {
TBLT::iterator i = m_tbl.begin();
while(i != m_tbl.end()) {
delete (*i);
m_tbl.erase(i);
}
}
 
void define(const char *key, AST *value) {
SYMTABLE_ENTRY *v = new SYMTABLE_ENTRY(key, value);
TBLT::iterator i = m_tbl.begin();
for(; (i!=m_tbl.end())&&(strcmp(key, (*i)->m_name.c_str())>0);
i++)
;
m_tbl.insert(i, v);
 
/*
fprintf(stderr, "Defining: %s = ", key);
value->dump(stderr);
fprintf(stderr, "\n");
*/
}
 
bool isdefined(const char *key) {
TBLT::iterator i = lookup(key);
if (i == m_tbl.end()) {
// fprintf(stderr, "%s is not in the symbol table\n", key);
return false;
} else {
bool defined = (*i)->isdefined();
/*
if (!defined) {
fprintf(stderr, "KEY: %s = ", key);
(*i)->dump(stderr);
fprintf(stderr, " is not yet defined\n");
} */
return (*i)->isdefined();
}
}
 
int value(const char *key) {
TBLT::iterator i = lookup(key);
if (i == m_tbl.end())
return 0;
else
return (*i)->val();
}
};
 
SYMBOL_TABLE *global_context = NULL, *file_context = NULL;
 
bool stb_isdefined(const char *key) {
if ((file_context)&&(file_context->isdefined(key)))
return true;
else
return global_context->isdefined(key);
} int stb_value(const char *key) {
if (file_context->isdefined(key))
return file_context->value(key);
else
return global_context->value(key);
} void stb_define(const char *key, AST *value) {
file_context->define(key, value);
} void gbl_define(const char *key, AST *value) {
global_context->define(key, value);
}
 
void create_new_context(void) {
if (global_context == NULL)
global_context = new SYMBOL_TABLE;
if (file_context != NULL)
delete file_context;
file_context = new SYMBOL_TABLE;
}
 
 
// Convenience functions for accessing the symbol table
bool stb_isdefined(const std::string &key) {
bool answer = stb_isdefined(key.c_str());
return answer;
} int stb_value(const std::string &key) {
return stb_value(key.c_str());
} void stb_define(const std::string &key, AST *value) {
stb_define(key.c_str(), value);
} void gbl_define(const std::string &key, AST *value) {
gbl_define(key.c_str(), value);
}
 
 
/zipcpu/trunk/sw/zasm/optest.cpp
4,7 → 4,10
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: A quick test of whether we can decode opcodes properly.
// Purpose: A quick test of whether we can decode opcodes properly. This
// test bypasses the assembler, and is useful when the assembler
// isn't working. Now that we've got the assembler running, this
// code isn't nearly as useful anymore.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
/zipcpu/trunk/sw/zasm/asmdata.h
0,0 → 1,283
////////////////////////////////////////////////////////////////////////////////
//
// Filename: asmdata.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: Data structures for the assembler. In particular, this file
// declares: Abstract Syntax Trees (ASTs) to store operations for
// later calculation, ASMLINEs or assembled lines (which may or
// may not be defined, depending upon symbol table status),
// symbol table access and the final output object file together
// with its necessary relocations. Yes, linking is done, but as
// part of the assembler and not part of a separate linker.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef ASMDATA_H
#define ASMDATA_H
 
#include <stdio.h>
#include <string>
#include <list>
#include "zopcodes.h"
#include "zparser.h"
 
extern "C" char *linecp;
 
typedef enum {
// TST OPCND
// Dual operand instructions that take conditions
OP_CMP, OP_TST, OP_MOV, OP_LDIHI, OP_LDILO, OP_MPY, OP_ROL,
OP_SUB, OP_AND, OP_ADD, OP_OR, OP_XOR,
OP_LSL, OP_ASR, OP_LSR,
// Memory operands/operators
OP_LOD, OP_STO,
// Dual operand instructions that do not take conditions
OP_LDI,
// Single operand instructions that can take conditions
OP_CLRF, OP_JMP, OP_LJMP, OP_NOT,
// Branch operands
OP_BRA, OP_BZ, OP_BNZ, OP_BGE, OP_BGT, OP_BLT, OP_BRC, OP_BRV,
// Single operand instructions that have no explicit conditions
OP_CLR, OP_TRAP,
// BAREOPs that can have conditions
OP_HALT, OP_RTU, OP_BUSY,
// BAREOPs without conditions
OP_BREAK, OP_NOOP,
// Error condition--undefined operand
OP_NONE
} LEXOPCODE;
 
#define DEFAULT_LINE 0x4e000000
 
class ASMLINE {
public:
char m_state;
virtual bool isdefined(void) { return true; };
virtual ~ASMLINE(void) {};
virtual int nlines(void) { return 0; }
virtual unsigned int eval(const int lno) { return DEFAULT_LINE; }
virtual void dump(FILE *fp) = 0;
};
 
class AST { // The actual expression tree
public:
// node type is one of:
// 'B' a branch with two sides
// 'N' a number
// 'I' an identifier
// 'A' ?? an address ?? would we need this?
char m_node_type;
virtual bool isdefined(void) = 0;
virtual int eval(void) = 0;
virtual void reduce(void) = 0;
virtual void dump(FILE *fp) = 0;
};
 
/*
class ULINE : public ASMLINE { // Unprocessed line of assembly
public:
std::string m_file, m_text;
int m_lineno;
ULINE(const int line, const std::string file,
const std::string text) : m_file(file), m_text(text),
m_lineno(line) { m_state = 'U'; }
class TLINE *eval(void);
int nlines(void) { return 0; };
virtual bool isdefined(void) { return false; };
};
*/
 
class ILINE : public ASMLINE { // Instruction line
public:
ZIPI m_in;
ILINE(const ZIPI in) : m_in(in) { m_state = 'I'; };
virtual bool isdefined(void) { return true; };
virtual int nlines(void) { return 1; }
virtual unsigned int eval(const int lno);
void dump(FILE *fp) { fprintf(fp, "IN: %08x\n", m_in); }
};
 
class VLINE : public ASMLINE { // Void line
public:
VLINE(void) { m_state = 'V'; };
virtual bool isdefined(void) { return true; };
virtual int nlines(void) { return 0; }
virtual unsigned int eval(const int lno);
void dump(FILE *fp) { fprintf(fp, "void\n"); }
};
 
class DLINE : public ASMLINE { // Data line
public:
ZIPI m_data;
DLINE(const ZIPI dat) : m_data(dat) { m_state = 'D'; };
virtual bool isdefined(void) { return true; };
virtual int nlines(void) { return 1; }
virtual unsigned int eval(const int lno);
void dump(FILE *fp) { fprintf(fp, "\tWORD\t%08d\n", m_data); }
};
 
class LLINE : public ASMLINE { // List line -- one line that has turned into
// many
public:
int m_nlines;
ASMLINE **m_lines;
LLINE(void) : m_nlines(0), m_lines(NULL) { m_state = 'L'; };
void addline(ASMLINE *line) ;
virtual bool isdefined(void);
~LLINE(void);
virtual int nlines(void) { return m_nlines; }
virtual unsigned int eval(const int lno);
void dump(FILE *fp) {
for(int i=0; i<m_nlines; i++)
m_lines[i]->dump(fp);
}
};
 
class TLINE : public ASMLINE { // Expression tree
public:
LEXOPCODE m_opcode;
ZPARSER::ZIPCOND m_cond;
AST *m_imm;
ZPARSER::ZIPREG m_opb, m_opa;
 
TLINE(void) : m_opcode(OP_NONE), m_cond(ZPARSER::ZIPC_ALWAYS),
m_imm(NULL), m_opa(ZPARSER::ZIP_Rnone), m_opb(ZPARSER::ZIP_Rnone)
{ m_state = 'T'; };
virtual bool isdefined(void) {
if (m_imm != NULL) {
bool answer = m_imm->isdefined();
return answer;
} else return true;
}
ASMLINE *eval(void);
~TLINE(void) { if (m_imm) delete m_imm; }
virtual int nlines(void); // { return 1; }
virtual unsigned int eval(const int lno);
void dump(FILE *fp);
};
 
class AST_BRANCH : public AST { // The actual expression tree
public:
int m_op; // An operator
AST *m_left, *m_right;
 
AST_BRANCH(int op, AST *l, AST *r)
: m_op(op), m_left(l), m_right(r) { m_node_type = 'B';
}
 
bool isdefined(void) {
return ((m_left)&&(m_right)
&&(m_left->isdefined())
&&(m_right->isdefined()));
}
~AST_BRANCH(void) { delete m_left; delete m_right; }
int eval(void);
void reduce(void);
void dump(FILE *fp) {
fprintf(fp, "(");
m_left->dump(fp);
fprintf(fp, ") %c (", m_node_type);
m_right->dump(fp);
fprintf(fp, ")");
}
};
 
class AST_NUMBER : public AST { // A number at the base of the tree
public:
int m_val;
AST_NUMBER(int val) : m_val(val) { m_node_type = 'N'; }
bool isdefined(void) { return true; }
int eval(void);
void reduce(void);
void dump(FILE *fp) { fprintf(fp, "%d", m_val); }
};
 
class AST_IDENTIFIER : public AST { // An identifier within the expression tree
public:
std::string m_id;
AST_IDENTIFIER(const char *id) : m_id(id) { m_node_type = 'I'; }
AST_IDENTIFIER(AST *ida, const char *idb);
bool isdefined(void);
int eval(void);
void reduce(void);
void dump(FILE *fp) { fprintf(fp, "%s", m_id.c_str()); }
};
 
class AST_LABEL : public AST { // An address label within the expression tree
// This is special, because it cannot be evaluated without knowing
// the PC value at this address
public:
std::string m_label;
AST_LABEL(const char *id) : m_label(id) { m_node_type = 'L'; }
bool isdefined(void);
int eval(void);
void reduce(void);
void dump(FILE *fp) { fprintf(fp, "%s", m_label.c_str()); }
};
 
class SAVED_ASMLINE {
public:
unsigned int m_pc;
ASMLINE *m_ln;
SAVED_ASMLINE(const unsigned int pc, ASMLINE *ln) : m_pc(pc), m_ln(ln)
{}
};
 
class OBJFILE {
typedef std::list<SAVED_ASMLINE> SVDTBL;
 
SVDTBL m_tbl;
unsigned int m_pc;
FILE *m_fp;
 
public:
OBJFILE(void) { m_fp = NULL; m_pc = 0; }
void open(const char *fname);
unsigned int pc(void) { return m_pc; }
void operator+=(ASMLINE *ln);
bool reduce(void);
};
 
// The file we are building
extern OBJFILE objcode;
 
// Functions for accessing and defining elements in our symbol table
extern bool stb_isdefined(const char *key);
extern int stb_value(const char *key);
extern void stb_define(const char *key, AST *value);
extern void gbl_define(const char *key, AST *value);
extern bool stb_isdefined(const std::string &key); // { return stb_isdefined(key.c_str()); }
extern int stb_value(const std::string &key); // { return stb_value(key.c_str()); }
extern void stb_define(const std::string &key, AST *value); // { return stb_define(key.c_str(), value); }
extern void gbl_define(const std::string &key, AST *value); // { return stb_define(key.c_str(), value); }
extern void create_new_context(void); // Create a new symbol table context
 
 
#endif // ASMDATA_H
/zipcpu/trunk/sw/zasm/zpp.l
0,0 → 1,309
/*******************************************************************************
**
** Filename: zpp.l
**
** Project: Zip CPU -- a small, lightweight, RISC CPU core
**
** Purpose: The preprocessor for the Zip Assembler.
**
** This routine strips comments, handles #define's, #ifdef's, and
** #include statements in a C fashion.
**
** #define macro's are also defined in the language and therefore
** supposed to be supported, but the support isn't there yet.
**
** Creator: Dan Gisselquist, Ph.D.
** Gisselquist Tecnology, LLC
**
********************************************************************************
**
** Copyright (C) 2015, Gisselquist Technology, LLC
**
** This program is free software (firmware): you can redistribute it and/or
** modify it under the terms of the GNU General Public License as published
** by the Free Software Foundation, either version 3 of the License, or (at
** your option) any later version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
** for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program. (It's in the $(ROOT)/doc directory, run make with no
** target there if the PDF file isn't present.) If not, see
** <http://www.gnu.org/licenses/> for a copy.
**
** License: GPL, v3, as defined and found on www.gnu.org,
** http://www.gnu.org/licenses/gpl.html
**
**
*******************************************************************************/
 
%{
// #include <FlexLexer.h>
#include <string>
#include <ctype.h>
#include <stdio.h>
#include <list>
 
using namespace std;
 
extern "C" int yylex();
// #include "zprepr.tab.h"
int ndef = 0;
void stb_define(const char *str);
void stb_args(const char *str);
void stb_macro(const char *value);
void stb_addmacro(const char *value);
bool stb_isdefined(const char *str);
const char *stb_getdefn(const char *str);
%}
%x DEF DFA DFV INDEF IFDEFV INNOTDEF NODEF NVRDEF COMMENT
%x INDEF_EOL INNOTDEF_EOL
%option noyywrap
%option stack
ID [_:A-Za-z][_:A-Za-z0-9]*
 
%%
<COMMENT>"*/" { yy_pop_state(); }
<COMMENT>[^*]+ { /* Ignore comments */ }
<COMMENT>"*"+[^/] { /* Ignore comments */ }
<INITIAL,INDEF>^"#include"[ \t]+\"[^\"]+\" {
char *ptr = &yytext[9], *start, *end, *str;
while(isspace(*ptr))
ptr++;
start = ptr;
ptr++;
while((*ptr)&&(*ptr != '\"'))
ptr++;
*ptr = '\0';
yypush_buffer_state(yy_create_buffer(
fopen(start, "r"),
YY_BUF_SIZE));
// push_file_state(yylineno); // and filename ...
fprintf(yyout, "#line 0 \"%s\"\n", start);
}
<INITIAL,INDEF>^"#define"[ \t]+ { yy_push_state(DEF); }
/* <*>^"#line"[ \t]+(0-9)+[ \t]+["][^"]*["][ \t]*\n { } */
<DEF>[_A-Za-z][_:A-Za-z0-9]*/[^(] {
stb_define(yytext);
BEGIN DFV;
}
<DEF>{ID}/[(] { fprintf(stderr, "DEF::Found MACRO\n");
stb_define(yytext);
BEGIN DFA; }
<DFA>([^)]+) {
/* Process arguments */
stb_args(yytext);
BEGIN DFV;
}
<DFV>[ \t]+ { /* Ignore initial spaces */ }
<DFV>[.]*$ {/* Parse to end of line, get value for our define */
// printf("End of define, value = \'%s\'\n", yytext);
stb_macro(yytext);
yy_pop_state();
}
<INITIAL,INDEF>^[ \t]+.[dD][aA][tT][aA]? { fprintf(yyout, "\tWORD"); }
<INITIAL,INDEF>^"#defcont"[ \t]+ { yy_push_state(DFV); }
<INITIAL,INDEF>^"#ifdef"[ \t]* { ndef = 0; yy_push_state(IFDEFV); }
<INITIAL,INDEF>^"#ifndef"[ \t]* { ndef = 1; yy_push_state(IFDEFV); }
<IFDEFV>{ID} {
bool known = stb_isdefined(yytext);
if ( ((known)&&(ndef==0)) || ((!known)&&(ndef!=0)) ) {
BEGIN INDEF_EOL;
} else {
BEGIN INNOTDEF_EOL;
}
}
/* Not yet: <INITIAL,INDEF>^"#if"[ \t]* { yy_push_state(IFDEFE); }
/* Not yet: <INITIAL,INDEF>^"#if"[ \t]* { yy_push_state(IFDEFE); }
/* Not yet: <IFDEFE><expr> { yy_push_state(IFDEFE); } */
/* <INNOTDEF>^"#elsif"[ \t]* { yy_pop_state(); yy_push_state(IFDEFE); } */
<INDEF_EOL>[ \t]*$ { BEGIN INDEF; }
<INDEF_EOL>(;|"//").*$ { BEGIN INDEF; }
<INNOTDEF_EOL>[ \t]*$ { BEGIN INNOTDEF; }
<INNOTDEF_EOL>(;|"//").*$ { BEGIN INNOTDEF; }
<INDEF_EOL>[^ \t\n].*$ { BEGIN INDEF; fprintf(stderr, "WARNING! Unexpected characters on IFDEF line, \'%s\'\n", yytext); }
<INNOTDEF_EOL>[^ \t\n].*$ { BEGIN INNOTDEF; fprintf(stderr, "WARNING! Unexpected characters on IFNDEF line, %s\n", yytext); }
<INDEF,NVRDEF>^"#else"[ \t]*((;|"//").*)?$ { BEGIN NODEF; }
<INNOTDEF>^"#else"[ \t]*((;|"//").*)?$ { BEGIN INDEF; }
<INNOTDEF>(.*) { }
<INDEF>^"#elsif"[ \t]* { BEGIN NVRDEF; }
<NODEF,INDEF,INNOTDEF>^"#endif"[ \t]*((;|"//").*)?$ { yy_pop_state(); }
<NODEF,INDEF,INNOTDEF>^"#endif"[ \t]*"/*" { BEGIN COMMENT; }
<*>^"#endif"[ \t]* { fprintf(stderr, "ERR: Unknown endif!!\n");}
/* Not yet: ^"#struct"[ \t]* {} */
/* Not yet: ^"#endstruct"[ \t]* {} */
/* Not yet: ^"#seg"[ \t]* {} */
<NODEF,NVRDEF>.* { /* Ignore everything in these states*/ }
<INITIAL,INDEF>{ID}/[^(] {
if (stb_isdefined(yytext))
fprintf(yyout, "%s", stb_getdefn(yytext));
else
fprintf(yyout, "%s", yytext);
}
<*>^[ \t]*"//".*$ { /* Ignore comment only lines */ }
<*>^[ \t]*";".*$ { /* Ignore comment only lines */ }
<*>"//".* { /* Ignore trailing comments */ }
<*>";".* { /* Ignore trailing comments */ }
<*>"/*" { yy_push_state(COMMENT); }
<*>[ \t]+ { ECHO; }
<INITIAL,INDEF>[.]* { ECHO; }
<*>\n { ECHO; }
/* <*>. { printf("Unmatched \'%c\'\n", yytext[0]); } */
/* <<EOF>> { printf("EOF!\n"); } */
 
%%
 
class SYMTABLE_ENTRY {
private:
std::string &trim(std::string &s) {
std::string::iterator ptr = s.end();
 
while((ptr >= s.begin())&&(isspace(*ptr)))
*ptr-- = '\0';
 
return s;
}
 
public:
std::string m_name, m_value, m_args;
SYMTABLE_ENTRY(const char *str) : m_name(str) {
trim(m_name);
}
SYMTABLE_ENTRY &operator+=(const char *str) {
const char *start = str;
 
while(isspace(*start))
start++;
if (m_value.length()!=0)
m_value += " ";
 
std::string trimd(start);
trim(trimd);
m_value += trimd;
 
/*
printf("ENTRY::SYMBOL \'%s\' NOW = \'%s\'\n",
m_name.c_str(), m_value.c_str());
*/
return *this;
}
SYMTABLE_ENTRY &setargs(const char *str) {
m_args += str;
return *this;
}
 
std::string getdefn(void) {
return m_value;
}
};
 
class SYMBOL_TABLE {
private:
typedef SYMTABLE_ENTRY *TBLV;
typedef std::list<TBLV> TBLT;
 
TBLT m_tbl;
TBLT::iterator lookup(const char *str) {
TBLT::iterator i = m_tbl.begin();
for(; (i!= m_tbl.end())&&(strcmp(str, (*i)->m_name.c_str())>0); i++)
;
if ((i != m_tbl.end())&&(strcmp(str, (*i)->m_name.c_str())==0))
return i;
return m_tbl.end();
}
 
public:
SYMBOL_TABLE(void) {}
 
void define(const char *str) {
SYMTABLE_ENTRY *v = new SYMTABLE_ENTRY(str);
TBLT::iterator i = m_tbl.begin();
for(; (i!= m_tbl.end())&&(strcmp(str, (*i)->m_name.c_str())>0); i++)
;
m_tbl.insert(i, v);
 
// printf("SYMS::Defining SYMBOL: \'%s\'\n", str);
}
 
bool defined(const char *str) {
TBLT::iterator i = lookup(str);
if (i==m_tbl.end())
return false;
else
return true;
}
 
 
void undefine(const char *str) {
TBLT::iterator i = lookup(str);
if (i == m_tbl.end())
return;
TBLV v = (*i);
m_tbl.erase(i);
delete v;
}
 
void addmacro(const char *name, const char *str) {
TBLT::iterator i = lookup(name);
if (i == m_tbl.end()) {
fprintf(stderr, "INTERNAL ERR, %s NOT DEFINED!\n", name);
} *(*i) += str;
}
void addargs(const char *name, const char *str) {
TBLT::iterator i = lookup(name);
if (i == m_tbl.end()) {
fprintf(stderr, "INTERNAL ERR, %s NOT DEFINED!\n", name);
} (*i)->setargs(str);
}
const char *getdefn(const char *name) {
TBLT::iterator i = lookup(name);
if (i == m_tbl.end()) {
fprintf(stderr, "INTERNAL ERR, %s NOT DEFINED!\n", name);
return NULL;
} (*i)->getdefn().c_str();
}
};
 
SYMTABLE_ENTRY *last = NULL;
SYMBOL_TABLE syms;
std::string last_define;
 
void stb_define(const char *str) {
if (syms.defined(str)) {
fprintf(stderr, "WARNING! Symbol \'%s\' is already defined!\n", str);
syms.undefine(str);
}
 
syms.define(str);
last_define = str;
}
 
void stb_args(const char *args) {
syms.addargs(last_define.c_str(), args);
}
 
void stb_macro(const char *value) {
syms.addmacro(last_define.c_str(), value);
}
 
void stb_addmacro(const char *value) {
syms.addmacro(last_define.c_str(),value);
}
 
bool stb_isdefined(const char *str) {
return syms.defined(str);
}
 
const char *stb_getdefn(const char *str) {
return syms.getdefn(str);
}
 
int main(int argc, char **argv) {
yylex();
}
 
/zipcpu/trunk/sw/zasm/zasm.l
0,0 → 1,167
/*******************************************************************************
**
** Filename: zasm.l
**
** Project: Zip CPU -- a small, lightweight, RISC CPU core
**
** Purpose: The lexical analyzer for the assembler. This converts assembler
** input into tokens, to feed the parser.
**
**
** Creator: Dan Gisselquist, Ph.D.
** Gisselquist Tecnology, LLC
**
********************************************************************************
**
** Copyright (C) 2015, Gisselquist Technology, LLC
**
** This program is free software (firmware): you can redistribute it and/or
** modify it under the terms of the GNU General Public License as published
** by the Free Software Foundation, either version 3 of the License, or (at
** your option) any later version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
** for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program. (It's in the $(ROOT)/doc directory, run make with no
** target there if the PDF file isn't present.) If not, see
** <http://www.gnu.org/licenses/> for a copy.
**
** License: GPL, v3, as defined and found on www.gnu.org,
** http://www.gnu.org/licenses/gpl.html
**
**
*******************************************************************************/
 
%{
#include <stdio.h>
#include "asmdata.h"
#include "zasm.tab.h"
 
extern "C" int yylex();
extern "C" int yywrap() { return 1;}
extern char *master_input_filename;
%}
 
%option yylineno
%option warn
 
%%
 
^"#line"[ \t]+[0-9]+[ \t]+["][^"]*["][ \t]*$ {
yylineno = atoi(&yytext[6]);
char *bg, *en;
bg = strchr(yytext, '\"')+1;
en = strchr(bg, '\"'); *en = '\0';
if ((master_input_filename == NULL)||(strcmp(master_input_filename, bg)!=0)) {
if (!master_input_filename) delete[] master_input_filename;
master_input_filename = new char[en-bg+2];
strcpy(master_input_filename, bg);
}
}
^"#line"[ \t]+[0-9]+[ \t]+$ { yylineno = atoi(&yytext[6]); }
[uU][rR]1[0-5] { yylval.u_reg=(ZPARSER::ZIPREG)(26+yytext[3]-'0');return REG; }
[sS][rR]1[0-5] { yylval.u_reg=(ZPARSER::ZIPREG)(10+yytext[3]-'0');return REG; }
[rR]1[0-5] { yylval.u_reg=(ZPARSER::ZIPREG)(10+yytext[2]-'0');return REG; }
[uU][rR][0-9] { yylval.u_reg=(ZPARSER::ZIPREG)(16+yytext[2]-'0');return REG; }
[sS][rR][0-9] { yylval.u_reg=(ZPARSER::ZIPREG)( yytext[2]-'0');return REG; }
[rR][0-9] { yylval.u_reg=(ZPARSER::ZIPREG)( yytext[1]-'0');return REG; }
[uU][pP][cC] { yylval.u_reg = ZPARSER::ZIP_uPC; return REG; }
[sS][pP][cC] { yylval.u_reg = ZPARSER::ZIP_PC; return REG; }
[pP][cC] { yylval.u_reg = ZPARSER::ZIP_PC; return REG; }
[uU][cC][cC] { yylval.u_reg = ZPARSER::ZIP_uCC; return REG; }
[sS][cC][cC] { yylval.u_reg = ZPARSER::ZIP_CC; return REG; }
[cC][cC] { yylval.u_reg = ZPARSER::ZIP_CC; return REG; }
[uU][sS][pP] { yylval.u_reg = ZPARSER::ZIP_uSP; return REG; }
[sS][sS][pP] { yylval.u_reg = ZPARSER::ZIP_SP; return REG; }
[sS][pP] { yylval.u_reg = ZPARSER::ZIP_SP; return REG; }
[bB][rR][aA] { yylval.u_op = OP_BRA; return BRANCHOP; }
[bB][rR][zZ] { yylval.u_op = OP_BZ; return BRANCHOP; }
[bB][zZ] { yylval.u_op = OP_BZ; return BRANCHOP; }
[bB][nN][zZ] { yylval.u_op = OP_BNZ; return BRANCHOP; }
[bB][nN][eE] { yylval.u_op = OP_BNZ; return BRANCHOP; }
[bB][gG][eE] { yylval.u_op = OP_BGE; return BRANCHOP; }
[bB][gG][tT] { yylval.u_op = OP_BGT; return BRANCHOP; }
[bB][gG] { yylval.u_op = OP_BGT; return BRANCHOP; }
[bB][lL][tT] { yylval.u_op = OP_BLT; return BRANCHOP; }
[bB][nN] { yylval.u_op = OP_BLT; return BRANCHOP; }
[bB][rR][cC] { yylval.u_op = OP_BRC; return BRANCHOP; }
[bB][cC] { yylval.u_op = OP_BRC; return BRANCHOP; }
[bB][rR][vV] { yylval.u_op = OP_BRV; return BRANCHOP; }
[bB][vV] { yylval.u_op = OP_BRV; return BRANCHOP; }
[cC][lL][rR] { yylval.u_op = OP_CLR; return SINGLOP; }
[cC][lL][rR][fF] {yylval.u_op = OP_CLRF;return SINGLOP; }
[iI][nN][tT] { yylval.u_op = OP_TRAP;return SINGLOP; }
[tT][rR][aA][pP] {yylval.u_op = OP_TRAP;return SINGLOP; }
[jJ][mM][pP] { yylval.u_op = OP_JMP; return SINGLOP; }
[lL][jJ][mM][pP] {yylval.u_op = OP_LJMP;return SINGLOP; }
[nN][oO][tT] { yylval.u_op = OP_NOT; return SINGLOP; }
[cC][mM][pP] { yylval.u_op = OP_CMP; return DUALOP; }
[tT][sS][tT] { yylval.u_op = OP_TST; return DUALOP; }
[mM][oO][vV] { yylval.u_op = OP_MOV; return DUALOP; }
[lL][dD][iI] { yylval.u_op = OP_LDI; return LDIOP; }
[lL][dD][iI][hH][iI] { yylval.u_op =OP_LDIHI; return LDHLOP; }
[lL][dD][iI][lL][oO] { yylval.u_op =OP_LDILO; return LDHLOP; }
[mM][pP][yY] { yylval.u_op = OP_MPY; return DUALOP; }
[rR][oO][lL] { yylval.u_op = OP_ROL; return DUALOP; }
[sS][uU][bB] { yylval.u_op = OP_SUB; return DUALOP; }
[aA][nN][dD] { yylval.u_op = OP_AND; return DUALOP; }
[aA][dD][dD] { yylval.u_op = OP_ADD; return DUALOP; }
[oO][rR] { yylval.u_op = OP_OR; return DUALOP;; }
[xX][oO][rR] { yylval.u_op = OP_XOR; return DUALOP; }
[lL][sS][lL] { yylval.u_op = OP_LSL; return DUALOP; }
[aA][sS][rR] { yylval.u_op = OP_ASR; return DUALOP; }
[lL][sS][rR] { yylval.u_op = OP_LSR; return DUALOP; }
[lL][oO][dD] { yylval.u_op = OP_LOD; return LOADOP; }
[sS][tT][oO] { yylval.u_op = OP_STO; return STOROP; }
[hH][aA][lL][tT] { yylval.u_op = OP_HALT; return BAREOP; }
[wW][aA][iI][tT] { yylval.u_op = OP_HALT; return BAREOP; }
[rR][tT][uU] { yylval.u_op = OP_RTU; return BAREOP; }
[nN][oO][pP] { yylval.u_op = OP_NOOP; return BAREOP; }
[nN][oO][oO][pP] { yylval.u_op = OP_NOOP; return BAREOP; }
[bB][rR][eE][aA][kK] { yylval.u_op = OP_BREAK; return BAREOP; }
[bB][rR][kK] { yylval.u_op = OP_BREAK; return BAREOP; }
[bB][uU][sS][yY] { yylval.u_op = OP_BUSY; return BAREOP; }
[eE][qQ][uU] { return EQU; }
[fF][iI][lL][lL] { return FILL; }
[wW][oO][rR][dD] { return WORD; }
"__"[hH][eE][rR][eE]"__" { return HERE; }
[\.][dD][aA][tT] { return WORD; }
[\.][zZ]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_Z; return COND; }
[\.][nN][eE]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_NZ; return COND; }
[\.][nN][zZ]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_NZ; return COND; }
[\.][gG][eE]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_GE; return COND; }
[\.][gG][tT]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_GT; return COND; }
[\.][lL][tT]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_LT; return COND; }
[\.][nN]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_LT; return COND; }
[\.][cC]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_C; return COND; }
[\.][vV]/[ \t\n] { yylval.u_cond = ZPARSER::ZIPC_V; return COND; }
[_A-Za-z][_a-zA-Z0-9]* { yylval.u_id = strdup(yytext); return IDENTIFIER; }
"$"?[-]?0[xX][0-9A-Fa-f]+ { yylval.u_ival = strtoul(yytext+(((*yytext)=='$')?1:0),NULL,16);return INT;}
"$"?[-]?0[0-7]+ { yylval.u_ival = strtoul(yytext+(((*yytext)=='$')?1:0),NULL, 8);return INT;}
"$"?[-]?[1-9][0-9]* { yylval.u_ival = strtoul(yytext+(((*yytext)=='$')?1:0),NULL,10);return INT;}
"$"?[-]?[1-9A-Fa-f][0-9A-Fa-f]*h {yylval.u_ival=strtoul(yytext+(((*yytext)=='$')?1:0),NULL,16); return INT;}
"$"?[-]?[0-7]+o { yylval.u_ival = strtoul(yytext+(((*yytext)=='$')?1:0),NULL, 8);return INT;}
"$"?"0" { yylval.u_ival = 0;return INT;}
"$" { return DOLLAR; }
"," { return COMMA; }
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return TIMES; }
"||" { return BOOLEANOR; }
"|" { return BITWISEOR; }
"&&" { return BOOLEANAND; }
"&" { return BITWISEAND; }
"^" { return BITWISEXOR; }
":" { return COLON; }
"." { return DOT; }
[ \t]+ { }
[(] { return '('; }
[)] { return ')'; }
\n.* { if (linecp) free(linecp); linecp = strdup(&yytext[1]); yyless(1); return '\n'; }
 
%%
 
/zipcpu/trunk/sw/zasm/sys.i
0,0 → 1,192
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Filename: sys.i
;
; Project: Zip CPU -- a small, lightweight, RISC CPU soft core
;
; Purpose: This is the beginnings of a system wide header file for the
; Zip System. It describes and declares the peripherals
; that will the be used and referenced by the assembly files.
;
; Status: As of August, 2015, I have no confidence that the preprocessor
; can properly include this file. It certainly cannot handle
; macros (yet).
;
; Creator: Dan Gisselquist, Ph.D.
; Gisselquist Tecnology, LLC
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Copyright (C) 2015, Gisselquist Technology, LLC
;
; This program is free software (firmware): you can redistribute it and/or
; modify it under the terms of the GNU General Public License as published
; by the Free Software Foundation, either version 3 of the License, or (at
; your option) any later version.
;
; This program is distributed in the hope that it will be useful, but WITHOUT
; ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
; for more details.
;
; License: GPL, v3, as defined and found on www.gnu.org,
; http://www.gnu.org/licenses/gpl.html
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
sys.bus equ 0xc0000000
sys.breaken equ 0x080
sys.step equ 0x040
sys.gie equ 0x020
sys.sleep equ 0x010
sys.ccv equ 0x008
sys.ccn equ 0x004
sys.ccc equ 0x002
sys.ccz equ 0x001
sys.bu.pic equ 0x000
sys.bus.wdt equ 0x001
sys.bus.cache equ 0x002
sys.bus.ctrpic equ 0x003
sys.bus.tma equ 0x004
 
 
 
; Define the location(s) of our peripherals,
#define sys.base 0xc0000000
#define sys.cache.base 0xc0100000
#struct sys
pic
wdt
cache
ctrpic
tma
tmb
tmc
jiffies
mtask
mstl
mpstl
mastl
utask
ustl
upstl
uastl
#endstruct
; and their associated interrupt vectors ...
#define CACHEINT 0x01
#define JIFFYINT 0x02 ;
#define TMCINT 0x04 ;
#define TMBINT 0x08 ;
#define TMAINT 0x10 ;
#define CTRPICINT 0x20 ; The aux interrupt controller
; Masks to send to enable those same vectors
#define CACHEINTEN 0x80010000
#define JIFFYINTEN 0x80020000
#define TMCINTEN 0x80040000
#define TMBINTEN 0x80080000
#define TMAINTEN 0x80100000
#define CTRPICEN 0x80200000
; And similar masks to disable them
#define CACHEINTDIS 0x00010000
#define JIFFYINTDIS 0x00020000
#define TMCINTDIS 0x00040000
#define TMBINTDIS 0x00080000
#define TMAINTDIS 0x00100000
#define CTRPICDIS 0x00200000
 
; Define our condition code bits
#define CCZ 0x001
#define CCC 0x002
#define CCN 0x004
#define CCV 0x008
#define CCSLEEP 0x010
#define CCGIE 0x020
#define CCSTEP 0x040
#define CCUBRK 0x080
 
; Now, some macros
#define PUSH(RG,SP) SUB 1,SP \
STO RG,-1(SP)
#define POP(RG,SP) LOD -1(SP),RG \
ADD 1,SP
#define FJSR(LBL,RG) MOV __here__+2(PC),RG \
JMP LBL
#define FRET(RG) MOV RG,PC
#define JSR(LBL,RG) SUB 1,SP \
MOV __here__+3(PC),RG \
STO RG,-1(SP) \
JMP LBL \
ADD 1,SP
#define RET LOD -1(SP),PC
#define SAVE_USER_CONTEXT(DR,AR) \
MOV -16(uSP),AR \
MOV uPC,DR \
STO DR,-16(AR) \
MOV uCC,DR \
STO DR,-15(AR) \
MOV uSP,DR \
STO DR,-14(AR) \
MOV uR12,DR \
STO DR,-13(AR) \
MOV uR11,DR \
STO DR,-12(AR) \
MOV uR10,DR \
STO DR,-11(AR) \
MOV uR9,DR \
STO DR,-10(AR) \
MOV uR8,DR \
STO DR,-9(AR) \
MOV uR7,DR \
STO DR,-8(AR) \
MOV uR6,DR \
STO DR,-7(AR) \
MOV uR5,DR \
STO DR,-6(AR) \
MOV uR4,DR \
STO DR,-5(AR) \
MOV uR3,DR \
STO DR,-4(AR) \
MOV uR2,DR \
STO DR,-3(AR) \
MOV uR1,DR \
STO DR,-2(AR) \
MOV uR0,DR \
STO DR,-1(AR)
#define RESTORE_USER_CONTEXT(DR,AR) \
LOD -1(AR),DR \
MOV DR,uR0 \
LOD -2(AR),DR \
MOV DR,uR1 \
LOD -3(AR),DR \
MOV DR,uR2 \
LOD -4(AR),DR \
MOV DR,uR3 \
LOD -5(AR),DR \
MOV DR,uR4 \
LOD -6(AR),DR \
MOV DR,uR5 \
LOD -7(AR),DR \
MOV DR,uR6 \
LOD -8(AR),DR \
MOV DR,uR7 \
LOD -9(AR),DR \
MOV DR,uR8 \
LOD -10(AR),DR \
MOV DR,uR9 \
LOD -11(AR),DR \
MOV DR,uR10 \
LOD -12(AR),DR \
MOV DR,uR11 \
LOD -13(AR),DR \
MOV DR,uR12 \
LOD -14(AR),DR \
MOV DR,uSP \
LOD -15(AR),DR \
MOV DR,uCC \
LOD -16(AR),DR \
MOV DR,uPC
#define READ_USER_TRAP(RG) \
MOV uCC,RG \
AND -256,RG
 
/zipcpu/trunk/sw/zasm/zopcodes.cpp
4,7 → 4,10
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose:
// Purpose: A simple program to handle the disassembly and definition
// of the various Zip Assembly opcodes. The primary function
// of this file is the zipi_to_string, or Zip Instruction to
// string (disassemble) conversion.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
65,6 → 68,7
// Special case instructions. These are general instructions, but with
// special opcodes
// Conditional branches
"BUSY", 0xffffffff, 0x2f0f7fff, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
"BRA", 0xffff8000, 0x2f0f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
"BRZ", 0xffff8000, 0x2f2f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
"BNZ", 0xffff8000, 0x2f4f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
/zipcpu/trunk/sw/zasm/zparser.cpp
4,7 → 4,14
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose:
// Purpose: This file is really mis-named. At one time it was going to
// be the parser for the Zip Assembler, zasm. Since then, I
// discovered Flex and Bison and have written a parser using
// those tools. The true parser may therefore be found in zasm.y.
// This file, however, still contains some very valuable tools.
// In particular, all of the routines used to build instructions
// from the appropriate fields are kept in this file. For example,
// op_noop() returns the instruction code for a NOOP instruction.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
45,359 → 52,6
 
typedef ZPARSER::ZIPI ZIPI; // A Zip Instruction (i.e. uint32)
 
bool ZPARSER::iscomment(const char *line) const {
const char *sp = line;
do {
if (*sp == '\0')
return true;
else if (*sp == ';')
return true;
else if (*sp == '#')
return true;
else if (*sp == '\n')
return true;
else if (*sp == '\r')
return true;
else if ((*sp == '/')&&(sp[1] == '/'))
return true;
else if (!isspace(*sp))
return false;
} while(*sp++);
 
return true;
}
 
bool ZPARSER::islabel(const char *line) const {
const char *sp = line;
if (isspace(*line))
return false;
if (!isalpha(*line))
return false;
while((isalpha(*sp))||(isdigit(*sp))||(*sp=='_'))
sp++;
if (*sp != ':')
return false;
sp++;
return iscomment(sp);
}
 
bool ZPARSER::parse_op(const char *line, ZPARSER::ZIPA pc,
ZPARSER::ZIPI &ins, const unsigned lineno) const {
const char *sp = line;
char cpy[128], *cp = cpy, *point, *dollar, *plus, *comma, *paren,
*opc, *opb, *opa;
ZPARSER::ZIPREG ra = ZPARSER::ZIP_Rnone, rb = ZPARSER::ZIP_Rnone;
ZIPCOND cnd = ZIPC_ALWAYS;
ZIPIMM imm = 0;
bool valid = true;
 
if (!isspace(*sp))
return false;
 
while(isspace(*sp))
sp++;
// Remove comments from our local copy
for(unsigned int i=0; i<sizeof(cpy); i++) {
if (*sp == '\0')
break;
else if (*sp == ';')
break;
else if (*sp == '#')
break;
else if (*sp == '\n')
break;
else if (*sp == '\r')
break;
else if ((*sp == '/')&&(sp[1] == '/'))
break;
*cp++ = *sp++;
} if (cp-cpy >= (int)sizeof(cpy))
return false;
*cp = '\0';
point = strchr(cpy, '.');
comma = strchr(cpy, ',');
plus = strchr(cpy, '+');
dollar= strchr(cpy, '$');
paren = strchr(cpy, '(');
if (point) *point++ = '\0';
if (comma) *comma++ = '\0';
if (plus) *plus++ = '\0';
if (dollar) *dollar++ = '\0';
// if (paren) *paren++ = '\0';
cp = cpy;
while(isalpha(*cp))
cp++;
opc = cpy;
if ((*cp == '\0')&&(point == NULL))
cp[1] = '\0';
*cp = '\0';
 
if ((point)&&(strncasecmp("DAT",point,3)!=0)) {
cp = point;
while(isalpha(*cp))
cp++;
if (*cp == '\0')
cp[1] = '\0';
*cp = '\0';
 
for(int i=1; i<8; i++) {
if (strcasecmp(&zop_ccstr[i][1], point)==0) {
cnd = (ZIPCOND)i;
break;
}
} if (cnd == ZIPC_ALWAYS) {
printf("ERR: Unrecognized condition, %s\n", point);
valid = false;
}
}
 
cp++;
while(isspace(*cp))
cp++;
opb = cp;
opa = comma;
 
if (paren) {
opb = paren+1;
if ((comma)&&(opb > comma))
opa = cp;
} else if (plus)
opb = plus;
if (dollar) {
// Figure out the base
{
char *ip = dollar, mxd = 0;
if ((*ip == '0')&&(toupper(ip[1])=='X'))
imm = strtoul(dollar, NULL, 16);
else {
bool neg = false;
if (*ip == '-') {
neg = true;
ip++;
dollar++;
}
while(isdigit(*ip)||((toupper(*ip)>='A')&&(toupper(*ip)<='F'))) {
if (isalpha(*ip))
mxd = (*ip-'a')+10;
else
mxd = (*ip-'0');
ip++;
}
 
if ((mxd <= 1)&&(*ip=='d'))
imm = strtoul(dollar, NULL, 2);
else if ((mxd <= 7)&&((*dollar == '0')||(toupper(*ip)=='O')))
imm = strtoul(dollar, NULL, 8);
else if ((mxd <= 15)&&(toupper(*ip)=='H'))
imm = strtoul(dollar, NULL, 16);
else if ((toupper(*ip)=='D')||(*ip == '+')||(isspace(*ip))||(*ip == '(')||(*ip == '\0'))
imm = atoi(dollar);
else {
printf("Cannot parse immediate, %s\n", dollar);
printf("Assuming you meant %d\n", atoi(dollar));
imm = atoi(dollar);
}
 
if (neg)
imm = -imm;
}
}
} else
imm = 0;
 
if (*opb) for(int i=31; i>=0; i--) {
// printf("%s Checking for match to opB: \'%s\' to %s", opc, opb, zop_regstr[i]);
if (NULL != strcasestr(opb, zop_regstr[i])) {
// printf(" --- Match\n");
rb = (ZIPREG)i;
break;
} // else printf(" -- nope\n");
} if (opa) for(int i=31; i>=0; i--) {
// printf("%s Checking for match to opA: ,%s to %s", opc, opa, zop_regstr[i]);
if (NULL != strcasestr(opa, zop_regstr[i])) {
ra = (ZIPREG)i;
// printf(" --- Match\n");
break;
} // else printf(" -- nope\n");
}
 
if (strcasecmp("MOV",opc)!=0) {
// Only move instructions can reference user regs
if ((ra != ZIP_Rnone)&&(ra >= ZIP_uR0))
valid = false;
if ((rb != ZIP_Rnone)&&(rb >= ZIP_uR0))
valid = false;
if (!valid)
printf("ERR: Only Mov can specify user regs\n");
}
 
if ((!*opc)&&(strncasecmp("DAT",point,3)==0)) {
ins = imm;
valid = true;
} else if (strcasecmp("CMP",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_cmp(cnd, imm, rb, ra);
else ins = op_cmp(cnd, imm, ra);
} else if (strcasecmp("TST",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_tst(cnd, imm, rb, ra);
else if (!dollar)
ins = op_tst(cnd, ra);
else
ins = op_tst(cnd, imm, ra);
} else if (strcasecmp("MOV",opc)==0) {
if ((rb != ZIP_Rnone)&&(ra != ZIP_Rnone))
ins = op_mov(cnd, imm, rb, ra);
else { printf("ERR MOV, ra = %d, rb = %d, imm = %d, cnd = %d\nLine was: %s", (int)ra, (int)rb, (int)imm, (int)cnd, line); valid = false; }
} else if (strcasecmp("LDI",opc)==0) {
if ((rb == ZIP_Rnone)&&(cnd == ZIPC_ALWAYS))
ins = op_ldi(imm, ra);
else valid = false;
} else if (strcasecmp("trap",opc)==0) {
if ((rb == ZIP_Rnone)&&(rb == ZIP_Rnone))
ins = op_trap(cnd, imm);
else
valid = false;
} else if (strcasecmp("CLR",opc)==0) {
if ((ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
ins = op_clr(rb); // Good
else valid = false;
} else if ((strcasecmp("NOOP",opc)==0)||(strcasecmp("NOP",opc)==0)) {
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
ins = op_noop();
else { printf("ERR: NOP, ra=%d, rb=%d, dollar = %s\n",
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; }
} else if ((strcasecmp("BREAK",opc)==0)||(strcasecmp("BRK",opc)==0)) {
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
ins = op_break();
else { printf("ERR: BRK, ra=%d, rb=%d, dollar = %s\n",
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; }
} else if ((strcasecmp("LDIHI",opc)==0)||(strcasecmp("LODIHI",opc)==0)) {
if ((dollar)&&(ra != ZIP_Rnone))
ins = op_ldihi(cnd, imm, ra);
else valid = false;
} else if ((strcasecmp("LDILO",opc)==0)||(strcasecmp("LODILO",opc)==0)){
if ((dollar)&&(ra != ZIP_Rnone))
ins = op_ldilo(cnd, imm, ra);
else valid = false;
} else if ((strcasecmp("LOD",opc)==0)||(strcasecmp("LOAD",opc)==0)) {
if (rb != ZIP_Rnone)
ins = op_lod(cnd,imm,rb,ra);
else ins = op_lod(cnd,imm,ra);
} else if ((strcasecmp("STO",opc)==0)||(strcasecmp("STOR",opc)==0)) {
// printf("STO: Imm = %d, RA = %d, RB = %d\n", imm, ra, rb);
if (rb != ZIP_Rnone)
ins = op_sto(cnd,ra,imm,rb);
else ins = op_sto(cnd,ra,imm);
} else if (strcasecmp("SUB",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_sub(cnd,imm,rb,ra);
else ins = op_sub(cnd,imm,ra);
} else if (strcasecmp("AND",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_and(cnd,imm,rb,ra);
else ins = op_and(cnd,imm,ra);
} else if (strcasecmp("ADD",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_add(cnd,imm,rb,ra);
else ins = op_add(cnd,imm,ra);
} else if (strcasecmp("OR",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_or(cnd,imm,rb,ra);
else ins = op_or(cnd,imm,ra);
} else if (strcasecmp("XOR",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_xor(cnd,imm,rb,ra);
else ins = op_xor(cnd,imm,ra);
} else if ((strcasecmp("LSL",opc)==0)||(strcasecmp("ASL",opc)==0)) {
if (rb != ZIP_Rnone)
ins = op_lsl(cnd,imm,rb,ra);
else ins = op_lsl(cnd,imm,ra);
} else if (strcasecmp("ASR",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_asr(cnd,imm,rb,ra);
else ins = op_asr(cnd,imm,ra);
} else if (strcasecmp("LSR",opc)==0) {
if (rb != ZIP_Rnone)
ins = op_lsr(cnd,imm,rb,ra);
else ins = op_lsr(cnd,imm,ra);
} else if (strcasecmp("BR",opc)==0) {
if ((dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone))
valid = false;
else ins = op_bra(cnd, imm);
} else if (strcasecmp("BRA",opc)==0) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_bra(imm);
} else if (strcasecmp("BRZ",opc)==0) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_brz(imm);
} else if ((strcasecmp("BRNZ",opc)==0)||(strcasecmp("BNZ",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_bnz(imm);
} else if ((strcasecmp("BRGE",opc)==0)||(strcasecmp("BGE",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_bge(imm);
} else if ((strcasecmp("BRGT",opc)==0)||(strcasecmp("BGT",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_bgt(imm);
} else if (strcasecmp("BRZ",opc)==0) {
} else if ((strcasecmp("BRLT",opc)==0)||(strcasecmp("BLT",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_blt(imm);
} else if ((strcasecmp("BRC",opc)==0)||(strcasecmp("BC",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_brc(imm);
} else if ((strcasecmp("BRV",opc)==0)||(strcasecmp("BV",opc)==0)) {
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
valid = false;
else ins = op_brv(imm);
} else if (strcasecmp("CLRF",opc)==0) {
if ((ra == ZIP_Rnone)&&(!dollar)&&(imm==0))
ins = op_clrf(cnd, rb);
else valid = false;
} else if((strcasecmp("HALT",opc)==0)||(strcasecmp("WAIT",opc)==0)) {
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
ins = op_halt(cnd);
else valid = false;
} else if (strcasecmp("BUSY",opc)==0) {
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
ins = op_busy(cnd);
else valid = false;
} else if (strcasecmp("RTU",opc)==0) {
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(imm==0)&&(!opa)&&(!dollar))
ins = op_rtu(cnd);
else { printf("ERRR,RTU, ra=%d,rb=%d,imm=%08x,comma=%s,dollar=%s\n",
(int)ra, (int)rb, imm, (opa)?"true":"false",
(dollar)?"true":"false");
valid = false;
}
} else if (strcasecmp("JMP",opc)==0) {
if ((rb != ZIP_Rnone)&&(!opa))
ins = op_not(cnd, rb);
else valid = false;
} else if (strcasecmp("NOT",opc)==0) {
if ((rb != ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
ins = op_not(cnd, rb);
else valid = false;
} else valid = false;
 
return valid;
}
 
bool ZPARSER::parse(const char *line, ZPARSER::ZIPA &pc, ZPARSER::ZIPI &instruction, const unsigned int lineno) {
bool v = parse_op(line, pc, instruction, lineno);
pc = pc + 1;
return v;
}
 
#define IMMOP(OP,CND,IMM,A) (((OP&0x0f)<<28)|((A&0x0f)<<24)|((CND&0x07)<<21) \
| (IMM & 0x0fffff))
 
439,8 → 93,12
 
ZIPI ZPARSER::op_trap(ZIPCOND cnd, ZIPIMM imm) const {
ZIPI in;
in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16);
in |= (imm & 0x0ffff);
if (cnd != ZIPC_ALWAYS)
return op_ldilo(cnd, imm, ZIP_CC);
else
return op_ldi(imm, ZIP_CC);
// in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16);
// in |= (imm & 0x0ffff);
return in;
}
 
/zipcpu/trunk/sw/zasm/obj-pc/depends.txt
1,3 → 1,4
obj-pc/asmdata.o: asmdata.cpp asmdata.h zopcodes.h zparser.h
obj-pc/optest.o: optest.cpp zopcodes.h
obj-pc/twoc.o: twoc.cpp twoc.h
obj-pc/zasm.o: zasm.cpp zopcodes.h zparser.h
/zipcpu/trunk/sw/zasm/zparser.h
4,7 → 4,14
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: The beginnings of a parser for Zip CPU assembly.
// Purpose: This file is really mis-named. At one time it was going to
// be header file for the parser for the Zip Assembler, zasm.
// Since then, I discovered Flex and Bison and have written a
// parser using those tools. The true parser may therefore be
// found in zasm.y. This file, however, still declares some
// very valuable tools. In particular, all of the routines used
// to build instructions from the appropriate fields are declared
// in this file.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
56,10 → 63,6
ZIPC_C, ZIPC_V
} ZIPCOND;
 
bool iscomment(const char *line) const;
bool islabel(const char *line) const;
bool parse_op(const char *line, ZIPA pc, ZIPI &instruction, const unsigned lineno) const;
bool parse(const char *line, ZIPA &pc, ZIPI &instruction, const unsigned lineno);
 
ZIPI op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const;
ZIPI op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const;
/zipcpu/trunk/sw/zasm/zopcodes.h
48,7 → 48,7
#define IMMFIELD(LN,MN) (0x40000000 + (((LN&0x0ff)<<8)+(MN&0x0ff))) // Sgn extnd
// #define REGVAL(V) ((V & 0x0f)+0x020)
 
typedef unsigned int ZIPI;
typedef unsigned int ZIPI; // A Zip CPU instruction
 
typedef struct {
char s_opstr[8];
/zipcpu/trunk/sw/zasm/Makefile
4,9 → 4,19
#
# Project: Zip CPU -- a small, lightweight, RISC CPU soft core
#
# Purpose: This makefile builds an assembler and disassembler.
# Purpose: This makefile builds an assembler preprocessor (zpp), an
# assembler (zasm) and a disassembler (zdump). Make with no
# arguments will produce these files. Other targets include:
#
# make clean
# make test
# Assembles a test file and then produces a disassembly of it.
# make depends
# Doesn't work. Dependencies are currently all hand coded.
# make optest
# make tags
#
#
# Creator: Dan Gisselquist, Ph.D.
# Gisselquist Tecnology, LLC
#
30,16 → 40,16
#
################################################################################
#
.PHONY: all
all: zasm optest zdump
OBJDIR= obj-pc
CXX= g++
CC= gcc
YACC= bison
LEX= flex
YYMMDD=`date +%Y%m%d`
DBGFLAGS= -g -O0
OPTFLAGS= -O3
CCFLAGS= $(DBGFLAGS)
PROGRAMS= zasm optest zdump
PROGRAMS= zasm optest zdump zpp
 
.PHONY: programs
all: $(OBJDIR)/ programs
46,11 → 56,29
 
programs: $(PROGRAMS)
 
ZASMSRC= zasm.cpp zopcodes.cpp zparser.cpp twoc.cpp
ZASMOBJ= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(ZASMSRC)))
zasm: $(ZASMOBJ)
$(CXX) $(CCFLAGS) $(ZASMOBJ) -o $@
$(OBJDIR)/zpp.cpp: zpp.l
$(LEX) -o $@ $^
$(OBJDIR)/zpp.o: $(OBJDIR)/zpp.cpp
$(CXX) -c $(CCFLAGS) $(OBJDIR)/zpp.cpp -o $@
zpp: $(OBJDIR)/zpp.o
$(CXX) -o $@ $(CCFLAGS) $^
 
$(OBJDIR)/zasm.tab.h: zasm.y asmdata.h zparser.h
$(YACC) -b $(OBJDIR)/zasm -d zasm.y
zasm.output: zasm.y asmdata.h
$(YACC) -v -b $(OBJDIR)/zasm -d zasm.y
$(OBJDIR)/zasm.lex.cpp: zasm.l $(OBJDIR)/zasm.tab.h
$(LEX) -o $@ zasm.l
$(OBJDIR)/zasm.lex.o: $(OBJDIR)/zasm.lex.cpp
$(CXX) -c -I. -I$(OBJDIR)/ $(CCFLAGS) $(OBJDIR)/zasm.lex.cpp -o $@
$(OBJDIR)/zasm.tab.o: $(OBJDIR)/zasm.tab.c
$(CXX) -c -I. -I$(OBJDIR)/ $(CCFLAGS) $(OBJDIR)/zasm.tab.c -o $@
$(OBJDIR)/asmdata.o: asmdata.cpp zopcodes.h zparser.h
$(CXX) -c -I. $(CCFLAGS) asmdata.cpp -o $@
zasm: $(OBJDIR)/zasm.lex.o $(OBJDIR)/zasm.tab.o $(OBJDIR)/asmdata.o
zasm: $(OBJDIR)/zparser.o $(OBJDIR)/zopcodes.o $(OBJDIR)/twoc.o
$(CXX) -o $@ $(CCFLAGS) $^
 
optest: optest.cpp zopcodes.cpp twoc.cpp twoc.h zopcodes.h
$(CXX) $(CCFLAGS) optest.cpp zopcodes.cpp twoc.cpp -o optest
 
65,9 → 93,16
$(OBJDIR)/:
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
 
.PHONY: test
test: dumpd.txt
z.out: test.S zasm zdump
./zasm test.S -o z.out
dumpd.txt: z.out zdump
./zdump z.out > dumpd.txt
 
define build-depends
@echo "Building dependency file(s)"
@$(CXX) $(CCFLAGS) -MM *.cpp > xd.txt
@$(CXX) -I $(OBJDIR)/ $(CCFLAGS) -MM *.cpp > xd.txt
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < xd.txt > $(OBJDIR)/depends.txt
@rm xd.txt
endef
80,19 → 115,13
depends: tags
$(build-depends)
 
$(OBJDIR)/depends.txt: $(OBJDIR)/ $(SOURCES) $(HEADERS)
$(OBJDIR)/depends.txt: $(SOURCES) $(HEADERS)
$(build-depends)
 
.PHONY: clean
clean:
rm -rf $(OBJDIR) $(PROGRAMS)
rm -rf $(OBJDIR) $(PROGRAMS) z.out dumpd.txt
 
-include $(OBJDIR)/depends.txt
 
 
 
 
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.