Compare commits
2 Commits
352518856d
...
760b1d9805
Author | SHA1 | Date |
---|---|---|
Denis Drakhnia | 760b1d9805 | |
Denis Drakhnia | 0e0d06070c |
106
src/e2k.S
106
src/e2k.S
|
@ -5,9 +5,15 @@
|
|||
#define CODE %r0
|
||||
#define TAPE %r1
|
||||
#define TAPE_SIZE %r2
|
||||
#define PC %r3
|
||||
#define CUR %r4
|
||||
#define ACC %r5
|
||||
#define STATS %r3
|
||||
#define PC %r4
|
||||
#define CUR %r5
|
||||
#define ACC %r6
|
||||
#define STATS_OPS %r7
|
||||
#define STATS_CALLS %r8
|
||||
#define STATS_BRANCHES %r9
|
||||
#define STATS_BRANCHES_TAKEN %r10
|
||||
#define STATS_CPU_CYCLES %r11
|
||||
|
||||
! Pipeline registers
|
||||
#define NPC_F %b[0]
|
||||
|
@ -40,7 +46,6 @@
|
|||
#define IS_NOT_TAKEN %pred29
|
||||
|
||||
#define LOOP %ctpr1
|
||||
#define PIPELINE %ctpr2
|
||||
#define CALL %ctpr3
|
||||
|
||||
.text
|
||||
|
@ -49,24 +54,34 @@
|
|||
.balign 8
|
||||
run_program_e2k:
|
||||
{
|
||||
setwd wsz=12, nfx=1, dbl=1
|
||||
setbn rsz=7, rbs=4, rcur=0
|
||||
setwd wsz=16, nfx=1, dbl=1
|
||||
setbn rsz=7, rbs=8, rcur=0
|
||||
setbp psz=13
|
||||
nop 4
|
||||
addd,1 TAPE, 0, CUR
|
||||
addd,2 0, 0, PC
|
||||
ldb,3 TAPE, 0, ACC
|
||||
disp PIPELINE, pipeline
|
||||
disp %ctpr1, pipeline
|
||||
}
|
||||
{
|
||||
nop 3
|
||||
ldd,0 STATS, 0, STATS_OPS
|
||||
ldd,2 STATS, 8, STATS_CALLS
|
||||
ldd,3 STATS, 16, STATS_BRANCHES
|
||||
ldd,5 STATS, 24, STATS_BRANCHES_TAKEN
|
||||
}
|
||||
{
|
||||
rrd,0 %clkr, STATS_CPU_CYCLES
|
||||
ct %ctpr1
|
||||
}
|
||||
ct PIPELINE
|
||||
|
||||
call:
|
||||
{
|
||||
setwd wsz=8, nfx=1, dbl=1
|
||||
setbn rsz=3, rbs=4, rcur=0
|
||||
setwd wsz=12, nfx=1, dbl=1
|
||||
setbn rsz=3, rbs=8, rcur=0
|
||||
setbp psz=0
|
||||
cmpedb,0 IMM_E, FUNC_PUTC, %pred31
|
||||
cmpedb,1 IMM_E, FUNC_GETC, %pred30
|
||||
addd,2 STATS_CALLS, 1, STATS_CALLS
|
||||
#ifdef FUNC_DEBUG
|
||||
cmpedb,3 IMM_E, FUNC_DEBUG, %pred29
|
||||
#endif
|
||||
|
@ -83,10 +98,10 @@ call:
|
|||
#endif
|
||||
{
|
||||
addd,0 ACC, 0, %b[0] ? %pred31
|
||||
call %ctpr1, wbs=4 ? %pred31
|
||||
call %ctpr1, wbs=8 ? %pred31
|
||||
}
|
||||
{
|
||||
call %ctpr2, wbs=4 ? %pred30
|
||||
call %ctpr2, wbs=8 ? %pred30
|
||||
}
|
||||
#ifdef FUNC_DEBUG
|
||||
{
|
||||
|
@ -95,12 +110,12 @@ call:
|
|||
addd,2 TAPE, 0, %b[2] ? %pred29
|
||||
addd,3 CUR, 0, %b[3] ? %pred29
|
||||
addd,4 ACC, 0, %b[4] ? %pred29
|
||||
call %ctpr3, wbs=4 ? %pred29
|
||||
call %ctpr3, wbs=8 ? %pred29
|
||||
}
|
||||
#endif
|
||||
{
|
||||
setwd wsz=12, nfx=1, dbl=1
|
||||
setbn rsz=7, rbs=4, rcur=0
|
||||
setwd wsz=16, nfx=1, dbl=1
|
||||
setbn rsz=7, rbs=8, rcur=0
|
||||
setbp psz=13
|
||||
addd,0 %b[0], 0, ACC ? %pred30
|
||||
}
|
||||
|
@ -109,7 +124,6 @@ call:
|
|||
! II0 - F - Fetch (latency 3)
|
||||
! II1 - D - Decode (latency 3)
|
||||
! II2 - E - Execute (latency 3-7)
|
||||
! TODO: branch prediction
|
||||
pipeline:
|
||||
{
|
||||
addd,0 PC, 4, NPC_E
|
||||
|
@ -118,10 +132,10 @@ pipeline:
|
|||
disp LOOP, loop
|
||||
}
|
||||
{
|
||||
nop 1
|
||||
ldw,2,sm CODE, NPC_E, INSN_D
|
||||
disp PIPELINE, pipeline
|
||||
}
|
||||
disp CALL, call
|
||||
}
|
||||
{
|
||||
cmpandesb,0,sm INSN_E, OP_MOV, IS_NOT_MOV_E
|
||||
cmpandesb,1,sm INSN_E, OP_BEQZ, IS_NOT_BEQZ_E
|
||||
|
@ -169,6 +183,8 @@ loop:
|
|||
pass @p6, IS_NOT_TAKEN
|
||||
}
|
||||
{
|
||||
addd,0 STATS_OPS, 1, STATS_OPS
|
||||
|
||||
! Decode
|
||||
cmpandesb,1,sm INSN_D, OP_ADD, IS_NOT_ADD_D
|
||||
cmpandesb,3,sm INSN_D, OP_EXE, IS_NOT_EXE_D
|
||||
|
@ -179,19 +195,57 @@ loop:
|
|||
ct LOOP ? ~IS_NOT_EXE_E
|
||||
}
|
||||
{
|
||||
! Execute (extra): exit pipeline and call function
|
||||
addd,1 NPC_E, 0, PC ? ~IS_NOT_CALL_E
|
||||
addd,3 NPC_E, 0, PC ? IS_NOT_TAKEN
|
||||
addd,4 BRANCH_TARGET_E, 0, PC ? ~IS_NOT_TAKEN
|
||||
|
||||
ldw,0,sm CODE, NPC_E, INSN_E ? IS_NOT_TAKEN
|
||||
ldw,2,sm CODE, BRANCH_TARGET_E, INSN_E ? ~IS_NOT_TAKEN
|
||||
|
||||
ct CALL ? ~IS_NOT_CALL_E
|
||||
}
|
||||
{
|
||||
! Execute (extra): restart pipeline
|
||||
addd,0 NPC_E, 0, PC ? IS_NOT_TAKEN
|
||||
addd,1 BRANCH_TARGET_E, 0, PC ? ~IS_NOT_TAKEN
|
||||
ct PIPELINE ? ~IS_NOT_BRANCH
|
||||
addd,0 NPC_E, 4, NPC_E ? IS_NOT_TAKEN
|
||||
addd,1 BRANCH_TARGET_E, 4, NPC_E ? ~IS_NOT_TAKEN
|
||||
addd,3 PC, 8, NPC_D
|
||||
}
|
||||
{
|
||||
nop 5
|
||||
ldw,2,sm CODE, NPC_E, INSN_D
|
||||
|
||||
addd,0 STATS_BRANCHES, 1, STATS_BRANCHES ? ~IS_NOT_BRANCH
|
||||
addd,1 STATS_BRANCHES_TAKEN, 1, STATS_BRANCHES_TAKEN ? ~IS_NOT_TAKEN
|
||||
}
|
||||
{
|
||||
cmpandesb,0,sm INSN_E, OP_MOV, IS_NOT_MOV_E
|
||||
cmpandesb,1,sm INSN_E, OP_BEQZ, IS_NOT_BEQZ_E
|
||||
getfd,2,sm INSN_E, 0x7686, IMM_E
|
||||
}
|
||||
{
|
||||
cmpandesb,0,sm INSN_E, OP_BNEZ, IS_NOT_BNEZ_E
|
||||
cmpandesb,1,sm INSN_E, OP_ADD, IS_NOT_ADD_E
|
||||
addd,2,sm NPC_E, IMM_E, BRANCH_TARGET_E
|
||||
cmpandesb,3,sm INSN_E, OP_EXE, IS_NOT_EXE_E
|
||||
cmpandesb,4,sm INSN_E, OP_CALL, IS_NOT_CALL_E
|
||||
|
||||
ct LOOP ? ~IS_NOT_BRANCH
|
||||
}
|
||||
{
|
||||
! remove end op from counter
|
||||
rrd,0 %clkr, %g16
|
||||
subd,1 STATS_OPS, 1, STATS_OPS
|
||||
return %ctpr3
|
||||
}
|
||||
{
|
||||
subd,0 %g16, STATS_CPU_CYCLES, STATS_CPU_CYCLES
|
||||
std,2 STATS_OPS, STATS, 0
|
||||
std,5 STATS_CALLS, STATS, 8
|
||||
}
|
||||
{
|
||||
std,2 STATS_BRANCHES, STATS, 16
|
||||
std,5 STATS_BRANCHES_TAKEN, STATS, 24
|
||||
}
|
||||
{
|
||||
nop 3
|
||||
std,2 STATS_CPU_CYCLES, STATS, 32
|
||||
}
|
||||
ct %ctpr3
|
||||
|
||||
|
|
48
src/main.c
48
src/main.c
|
@ -6,6 +6,7 @@
|
|||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <time.h>
|
||||
|
@ -14,6 +15,14 @@
|
|||
#define TAPE_SIZE 30000
|
||||
#define MAX_NESTING 100
|
||||
|
||||
typedef struct Stats {
|
||||
uint64_t ops;
|
||||
uint64_t calls;
|
||||
uint64_t branches;
|
||||
uint64_t taken_branches;
|
||||
uint64_t cpu_cycles;
|
||||
} Stats;
|
||||
|
||||
typedef enum Mode {
|
||||
MODE_ASM,
|
||||
MODE_BC,
|
||||
|
@ -25,6 +34,7 @@ typedef struct Options {
|
|||
bool dump;
|
||||
bool dump_only;
|
||||
bool time;
|
||||
bool stats;
|
||||
char **files;
|
||||
} Options;
|
||||
|
||||
|
@ -43,12 +53,13 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
|
|||
for (;;) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"mode", required_argument, 0, 'm'},
|
||||
{"dump", no_argument, 0, 'd'},
|
||||
{"dump-only", no_argument, 0, 'D'},
|
||||
{"mode", required_argument, 0, 'm'},
|
||||
{"stats", no_argument, 0, 's'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
int c = getopt_long(argc, argv, "dDm:t",
|
||||
int c = getopt_long(argc, argv, "dDm:ts",
|
||||
long_options, &option_index);
|
||||
if (c == -1) {
|
||||
break;
|
||||
|
@ -66,6 +77,9 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
|
|||
case 't':
|
||||
opts->time = true;
|
||||
break;
|
||||
case 's':
|
||||
opts->stats = true;
|
||||
break;
|
||||
case 'm':
|
||||
if (strcmp(optarg, "asm") == 0) {
|
||||
opts->mode = MODE_ASM;
|
||||
|
@ -95,7 +109,8 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
|
|||
}
|
||||
|
||||
#ifdef __e2k__
|
||||
void run_program_e2k(const int32_t *code, uint8_t *tape, size_t tape_size);
|
||||
void run_program_e2k(const int32_t *code, uint8_t *tape,
|
||||
size_t tape_size, Stats *stats);
|
||||
#endif
|
||||
|
||||
static inline int32_t make_insn(uint8_t op, int32_t n) {
|
||||
|
@ -235,22 +250,29 @@ static void dump_program(const char *path, const int32_t *code) {
|
|||
printf_err("\n");
|
||||
}
|
||||
|
||||
static void run_program_bc(const int32_t *code, uint8_t *tape, size_t tape_size) {
|
||||
static void run_program_bc(const int32_t *code, uint8_t *tape,
|
||||
size_t tape_size, Stats *stats)
|
||||
{
|
||||
uint32_t pc = 0, i = 0;
|
||||
uint8_t cur = tape[i];
|
||||
|
||||
for (; code[pc]; ++pc) {
|
||||
int32_t n = insn_imm(code[pc]);
|
||||
|
||||
stats->ops += 1;
|
||||
switch (code[pc] & OP_MASK) {
|
||||
case OP_BEQZ:
|
||||
stats->branches += 1;
|
||||
if (cur == 0) {
|
||||
pc += n / 4;
|
||||
stats->taken_branches += 1;
|
||||
}
|
||||
break;
|
||||
case OP_BNEZ:
|
||||
stats->branches += 1;
|
||||
if (cur != 0) {
|
||||
pc += n / 4;
|
||||
stats->taken_branches += 1;
|
||||
}
|
||||
break;
|
||||
case OP_ADD:
|
||||
|
@ -262,6 +284,7 @@ static void run_program_bc(const int32_t *code, uint8_t *tape, size_t tape_size)
|
|||
cur = tape[i];
|
||||
break;
|
||||
case OP_CALL:
|
||||
stats->calls += 1;
|
||||
switch (n) {
|
||||
case FUNC_GETC:
|
||||
cur = getchar();
|
||||
|
@ -323,6 +346,7 @@ int main(int argc, char *argv[], char *envp[]) {
|
|||
}
|
||||
|
||||
if (!opts.dump_only) {
|
||||
Stats stats = { 0 };
|
||||
struct timespec start;
|
||||
|
||||
memset(tape, 0, TAPE_SIZE);
|
||||
|
@ -336,12 +360,13 @@ int main(int argc, char *argv[], char *envp[]) {
|
|||
case MODE_BC:
|
||||
#if __e2k__
|
||||
if (opts.mode == MODE_ASM) {
|
||||
run_program_e2k(code, tape, TAPE_SIZE);
|
||||
run_program_e2k(code, tape, TAPE_SIZE, &stats);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
run_program_bc(code, tape, TAPE_SIZE);
|
||||
run_program_bc(code, tape, TAPE_SIZE, &stats);
|
||||
}
|
||||
|
||||
break;
|
||||
case MODE_NAIVE:
|
||||
run_program_naive(program, tape, TAPE_SIZE);
|
||||
|
@ -366,6 +391,17 @@ int main(int argc, char *argv[], char *envp[]) {
|
|||
|
||||
printf_err(" Time: %.2f%s\n", time, units);
|
||||
}
|
||||
|
||||
if (opts.stats) {
|
||||
printf_err(" Stats\n");
|
||||
printf_err(" ops: %" PRIu64 "\n", stats.ops);
|
||||
printf_err(" calls: %" PRIu64 "\n", stats.calls);
|
||||
printf_err(" branches: %" PRIu64 " (taken %" PRIu64 ")\n",
|
||||
stats.branches, stats.taken_branches);
|
||||
if (stats.cpu_cycles) {
|
||||
printf_err(" cpu cycles: %" PRIu64 "\n", stats.cpu_cycles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dump || opts.time) {
|
||||
|
|
Loading…
Reference in New Issue