1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00

Moving toward working test code

This commit is contained in:
Ross Wilson
2015-10-17 15:39:57 +07:00
parent 1880199a26
commit cf1e967b0e

View File

@@ -85,6 +85,33 @@ typedef struct _Test
} Test;
int UsedCycles = 0;
/******************************************************************************
Description : Convert a string value into a WORD integer.
Parameters : str - address of string holding [0-9] characters
Returns : A WORD value containing the integer number in 'str'.
Comments : 'str' may contain a decimal or octal string representation.
******************************************************************************/
WORD
str2word(char *str)
{
WORD value = 0;
if (*str == '0')
{ // octal
sscanf(str, "%o", &value);
}
else
{ // decimal
sscanf(str, "%d", &value);
}
return value;
}
/******************************************************************************
Description : Constructor for a Command struct.
Parameters : opcode - the opcode value for the struct
@@ -98,6 +125,8 @@ new_Command(char *opcode)
result->opcode = (char *) malloc(strlen(opcode)+1);
strcpy(result->opcode, opcode);
for (char *cptr = result->opcode; *cptr; ++cptr)
*cptr = tolower(*cptr);
result->next = NULL;
result->field1 = NULL;
@@ -131,13 +160,15 @@ new_Test(int line_number, Command *commands)
Description : Function to provide help to the befuddled user.
Parameters : msg - if not NULL, a message to display
Returns :
Comments :
Comments : String is converted to upper case.
******************************************************************************/
char *
new_String(char *str)
{
char *result = (char *) malloc(strlen(str)+1);
strcpy(result, str);
for (char *cptr = result; *cptr; ++cptr)
*cptr = tolower(*cptr);
return result;
}
@@ -179,7 +210,7 @@ Description : Function to return the imlac binary opcode of an instruction.
Comments : We generate an ASM file, assemble it and pick out the binary
: opcode from the LST file.
******************************************************************************/
int
WORD
assemble(WORD addr, char *opcode)
{
FILE *fd;
@@ -206,6 +237,7 @@ assemble(WORD addr, char *opcode)
error("Error reading %s", LstFilename);
if (sscanf(buffer, "%o", &result) != 1)
error("Badly formatted assembler output: %s", buffer);
fclose(fd);
return result;
}
@@ -250,39 +282,45 @@ parse_one_cmd(char *scan)
char *opcode;
char *field1 = NULL;
char *field2 = NULL;
char tmpbuff[16];
// find start and end of opcode
while (*scan && isspace(*scan))
while (*scan && isspace(*scan)) // skip leading space
++scan;
opcode = scan;
while (*scan && !isspace(*scan))
++scan;
*scan = '\0';
++scan;
if (*scan)
*(scan++) = '\0';
// start/end of field1 (if there)
while (*scan && isspace(*scan))
while (*scan && isspace(*scan)) // skip leading space
++scan;
if (*scan)
{
{ // we have field1, at least
field1 = scan;
while (*scan && !isspace(*scan))
++scan;
*scan = '\0';
++scan;
if (*scan)
*(scan++) = '\0';
// field2
while (*scan && isspace(*scan))
while (*scan && isspace(*scan)) // skip leading space
++scan;
if (*scan)
{
field2 = scan;
if (*field2 == '[')
{
{ // assembler field
++field2;
while (*scan && !(*scan == ']'))
++scan;
*scan = '\0';
WORD v = str2word(field1);
v = assemble(str2word(field1), field2);
sprintf(tmpbuff, "%d", v);
field2 = tmpbuff;
}
else
{
@@ -324,8 +362,6 @@ parse_cmds(char *scan)
char *end_cmd = NULL;
Command *new_cmd = NULL;
printf("parse_cmds: scan->%s\n", scan);
// scan the buffer for commands
do
{
@@ -341,13 +377,8 @@ parse_cmds(char *scan)
*end_cmd = '\0';
}
printf("parse_cmds: before parse_one_cmd(), scan->%s\n", scan);
new_cmd = parse_one_cmd(scan);
printf("parse_cmds: after parse_one_cmd(), result=%p, last_result=%p, new_cmd=%p\n", result, last_result, new_cmd);
fflush(stdout);
if (result == NULL)
{
result = new_cmd;
@@ -355,14 +386,11 @@ parse_cmds(char *scan)
}
else
{
printf("parse_cmds: last_result->next=%p\n", last_result->next);
last_result->next = new_cmd;
last_result = new_cmd;
}
scan = new_scan;
printf("parse_cmds: bottom of loop, scan=%p\n", scan);
fflush(stdout);
} while (scan && *scan);
@@ -417,32 +445,21 @@ parse_script(char *scriptpath)
if (should_skip(buffer))
continue;
// DEBUG
printf("%03d: %s\n", line_number, buffer);
// decide if line is new test or continuation
if (isspace(buffer[0]))
{ // continuation
printf("CONTINUE\n");
// test for continuation without first part of test
if (head_test == NULL)
error("Test continuation on first code line of test file!?");
Command *new_cmds = parse_cmds(buffer);
printf("Point 1, last_cmd=%p, last_cmd->next=%p\n", last_cmd, last_cmd->next); fflush(stdout);
last_cmd->next = new_cmds;
printf("Point 2\n"); fflush(stdout);
while (last_cmd->next)
last_cmd = last_cmd->next;
printf("Point 3\n"); fflush(stdout);
printf("END CONTINUE\n");
}
else
{ // new test
printf("NEW\n");
Test *new_test = new_Test(line_number, parse_cmds(buffer));
if (head_test == NULL)
@@ -458,10 +475,7 @@ parse_script(char *scriptpath)
// move 'last_cmd' to end of command chain
for (last_cmd = last_test->commands; last_cmd->next != NULL; last_cmd = last_cmd->next)
;
printf("END NEW, last_cmd=%p, last_cmd->next=%p\n", last_cmd, last_cmd->next);
}
fflush(stdout);
}
// close script file
@@ -471,6 +485,187 @@ parse_script(char *scriptpath)
}
/******************************************************************************
Description : Set a register to a value
Parameters : test - pointer to a Test struct
Returns : The number of errors encountered (0 or 1).
Comments : Sets globals used to check after execution.
******************************************************************************/
int
setreg(char *name, char *fld2)
{
int result = 0;
WORD value = str2word(fld2);
if (strcmp(name, "ac") == 0)
cpu_set_AC(value);
else if (strcmp(name, "l") == 0)
cpu_set_L(value);
else if (strcmp(name, "pc") == 0)
cpu_set_PC(value);
else if (strcmp(name, "ds") == 0)
cpu_set_DS(value);
else
{
printf("setreg: bad register name: %s\n", name);
result = 1;
}
return result;
}
/******************************************************************************
Description : Set a memory cell to a value;
Parameters : addr - address of memory cell (string)
: fld2 - value to put into cell (string)
Returns : The number of errors encountered (0 or 1).
Comments : Sets globals used to check after execution.
******************************************************************************/
int
setmem(char *addr, char *fld2)
{
WORD address = str2word(addr);
WORD value = str2word(fld2);
mem_put(address, false, value);
return 0;
}
/******************************************************************************
Description : Set a memory cell to a value;
Parameters : addr - address of memory cell (string)
: fld2 - value to put into cell (string)
Returns : The number of errors encountered (0 or 1).
Comments : Sets globals used to check after execution.
******************************************************************************/
int
run_one(char *addr, char *fld2)
{
WORD address = str2word(addr);
if (addr)
{ // force PC to given address
cpu_set_PC(address);
}
UsedCycles = cpu_execute_one();
return 0;
}
/******************************************************************************
Description : Set a memory cell to a value;
Parameters : addr - address of memory cell (string)
: fld2 - value to put into cell (string)
Returns : The number of errors encountered (0 or 1).
Comments : Sets globals used to check after execution.
******************************************************************************/
int
checkcycles(char *cycles, char *fld2)
{
WORD c = str2word(cycles);
if (c != UsedCycles)
{
printf("Test used %d cycles, exoected %d!?", UsedCycles, c);
return 1;
}
return 0;
}
#ifdef JUNK
def checkcycles(self, cycles, var2=None):
"""Check that opcode cycles used is correct."""
if cycles != self.used_cycles:
return 'Opcode used %d cycles, expected %d' % (self.used_cycles, cycles)
#endif
#ifdef JUNK
test_cpu.c:537:22: warning: implicit declaration of function 'run' is invalid in C99 [-Wimplicit-function-declaration]
error += run(fld1, fld2);
^
test_cpu.c:539:22: warning: implicit declaration of function 'checkcycles' is invalid in C99 [-Wimplicit-function-declaration]
error += checkcycles(fld1, fld2);
^
test_cpu.c:541:22: warning: implicit declaration of function 'checkreg' is invalid in C99 [-Wimplicit-function-declaration]
error += checkreg(fld1, fld2);
^
test_cpu.c:543:22: warning: implicit declaration of function 'checkmem' is invalid in C99 [-Wimplicit-function-declaration]
error += checkmem(fld1, fld2);
^
test_cpu.c:545:22: warning: implicit declaration of function 'allreg' is invalid in C99 [-Wimplicit-function-declaration]
error += allreg(fld1, fld2);
^
test_cpu.c:547:22: warning: implicit declaration of function 'allmem' is invalid in C99 [-Wimplicit-function-declaration]
error += allmem(fld1, fld2);
^
test_cpu.c:549:22: warning: implicit declaration of function 'checkrun' is invalid in C99 [-Wimplicit-function-declaration]
error += checkrun(fld1, fld2);
^
test_cpu.c:551:22: warning: implicit declaration of function 'setd' is invalid in C99 [-Wimplicit-function-declaration]
error += setd(fld1, fld2);
^
test_cpu.c:553:22: warning: implicit declaration of function 'checkd' is invalid in C99 [-Wimplicit-function-declaration]
error += checkd(fld1, fld2);
#endif
/******************************************************************************
Description : Run one test.
Parameters : test - pointer to a Test struct
Returns : The number of errors encountered (0 or 1).
Comments :
******************************************************************************/
int
run_one_test(Test *test)
{
int error = 0;
for (Command *cmd = test->commands; cmd; cmd = cmd->next)
{
char *opcode = cmd->opcode;
char *fld1 = cmd->field1;
char *fld2 = cmd->field2;
if (strcmp(opcode, "setreg"), 0)
error += setreg(fld1, fld2);
else if (strcmp(opcode, "setmem") == 0)
error += setmem(fld1, fld2);
else if (strcmp(opcode, "run") == 0)
error += run_one(fld1, fld2);
else if (strcmp(opcode, "checkcycles") == 0)
error += checkcycles(fld1, fld2);
else if (strcmp(opcode, "checkreg") == 0)
error += checkreg(fld1, fld2);
else if (strcmp(opcode, "checkmem") == 0)
error += checkmem(fld1, fld2);
else if (strcmp(opcode, "allreg") == 0)
error += allreg(fld1, fld2);
else if (strcmp(opcode, "allmem") == 0)
error += allmem(fld1, fld2);
else if (strcmp(opcode, "checkrun") == 0)
error += checkrun(fld1, fld2);
else if (strcmp(opcode, "setd") == 0)
error += setd(fld1, fld2);
else if (strcmp(opcode, "checkd") == 0)
error += checkd(fld1, fld2);
else
{
printf("Unrecognized operation '%s' at line %d\n",
opcode, test->line_number);
error += 1;
}
}
return error;
}
/******************************************************************************
Description : Run tests and collect number of errors.
Parameters : test - pointer to a chain if Test structs
@@ -482,6 +677,16 @@ run(Test *test)
{
int errors = 0;
while (test)
{
printf("Test from line %d, test->next=%p\n", test->line_number, test->next);
fflush(stdout);
errors += run_one_test(test);
test = test->next;
}
return errors;
}
@@ -495,15 +700,12 @@ Description : Function to execute test script.
int
execute(char *script)
{
printf("execute: ENTER\n");
Test *test = NULL; // chain of test commands
// get test commands into massaged form in memory
test = parse_script(script);
printf("execute: test=%p\n", test);
//#ifdef DEBUG
// DEBUG - print contents of 'test'
for (Test *tscan = test; tscan != NULL; tscan = tscan->next)
{
@@ -515,6 +717,7 @@ execute(char *script)
printf("\n");
fflush(stdout);
}
//#endif
// execute tests
return run(test);
@@ -551,11 +754,10 @@ main(int argc, char *argv[])
// get filename and make sure it's there
script = argv[optind];
if ((script_fd = fopen(script, "r")) == NULL)
{
if ((script_fd = fopen(script, "rb")) == NULL)
error("File %s doesn't exist or isn't readable: %d\n",
script, errno);
}
fclose(script_fd);
errors = execute(script);
@@ -566,92 +768,6 @@ main(int argc, char *argv[])
#ifdef JUNK
import os
from Globals import *
import MainCPU
import Memory
import Trace
import log
log = log.Log('test_CPU.log', log.Log.DEBUG)
class TestCPU(object):
# temporary assembler file and listfile prefix
AsmFilename = '_#ASM#_'
def __init__(self):
"""Initialize the test."""
pass
def assemble(self, addr, opcode):
"""Assemble a single instruction, return opcode."""
# create ASM file with instruction
with open(self.AsmFilename+'.asm', 'wb') as fd:
fd.write('\torg\t%07o\n' % addr)
fd.write('\t%s\n' % opcode[1:-1])
fd.write('\tend\n')
# now assemble file
#cmd = '../iasm/iasm -l %s.lst %s.asm >xyzzy 2>&1' % (self.AsmFilename, self.AsmFilename)
cmd = '../iasm/iasm -l %s.lst %s.asm' % (self.AsmFilename, self.AsmFilename)
res = os.system(cmd)
# read the listing file to get assembled opcode (second line)
with open(self.AsmFilename+'.lst', 'rb') as fd:
lines = fd.readlines()
line = lines[1]
(opcode, _) = line.split(None, 1)
return int(opcode, base=8)
def setreg(self, name, value):
"""Set register to a value.
Remember value to check later.
"""
self.reg_values[name] = value
if name == 'ac':
self.cpu.AC = value
elif name == 'l':
self.cpu.L = value & 1
elif name == 'pc':
self.cpu.PC = value
elif name == 'ds':
self.cpu.DS = value
else:
raise Exception('setreg: bad register name: %s' % name)
def setmem(self, addr, value):
"""Set memory location to a value."""
if isinstance(value, basestring):
log.debug('setmem: addr=%s, value=%s' % (oct(addr), value))
else:
log.debug('setmem: addr=%s, value=%s' % (oct(addr), oct(value)))
# check if we must assemble var2
if isinstance(value, basestring) and value[0] == '[':
# assemble an instruction
value = self.assemble(addr, value)
log.debug('setmem: assembled opcode=%07o' % value)
self.mem_values[addr] = value
log.debug('setmem: After, MemValues=%s' % str(self.mem_values))
self.memory.put(value, addr, False)
log.debug('setmem: After, Memory at %07o is %07o' % (addr, self.memory.fetch(addr, False)))
def allmem(self, value, ignore=None):
"""Set all of memory to a value.
@@ -824,8 +940,6 @@ class TestCPU(object):
# set globals
self.reg_values = {}
self.mem_values = {}
#self.reg_all_value = {}
#self.mem_all_value = {}
self.reg_all_value = 0
self.mem_all_value = 0