X-Git-Url: https://git.stderr.nl/gitweb?p=projects%2Fchimara%2Fchimara.git;a=blobdiff_plain;f=interpreters%2Fbocfel%2Fmath.c;fp=interpreters%2Fbocfel%2Fmath.c;h=925391d2f631898cace532e34cc5b0973bbc8dac;hp=0000000000000000000000000000000000000000;hb=aa30979369091c96bca34499c28cb01bc16efb1d;hpb=61180dab8f5c29f5a29b83fcb7d62942f7a741d1 diff --git a/interpreters/bocfel/math.c b/interpreters/bocfel/math.c new file mode 100644 index 0000000..925391d --- /dev/null +++ b/interpreters/bocfel/math.c @@ -0,0 +1,166 @@ +/*- + * Copyright 2010-2012 Chris Spiegel. + * + * This file is part of Bocfel. + * + * Bocfel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version + * 2 or 3, as published by the Free Software Foundation. + * + * Bocfel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 Bocfel. If not, see . + */ + +#include + +#include "math.h" +#include "branch.h" +#include "process.h" +#include "stack.h" +#include "util.h" +#include "zterp.h" + +void zinc(void) +{ + store_variable(zargs[0], variable(zargs[0]) + 1); +} + +void zdec(void) +{ + store_variable(zargs[0], variable(zargs[0]) - 1); +} + +void znot(void) +{ + store(~zargs[0]); +} + +void zdec_chk(void) +{ + int16_t new; + int16_t val = zargs[1]; + + zdec(); + + /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */ + if(zargs[0] == 0) new = *stack_top_element(); + else new = variable(zargs[0]); + + branch_if(new < val); +} + +void zinc_chk(void) +{ + int16_t new; + int16_t val = zargs[1]; + + zinc(); + + /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */ + if(zargs[0] == 0) new = *stack_top_element(); + else new = variable(zargs[0]); + + branch_if(new > val); +} + +void ztest(void) +{ + branch_if( (zargs[0] & zargs[1]) == zargs[1] ); +} + +void zor(void) +{ + store(zargs[0] | zargs[1]); +} + +void zand(void) +{ + store(zargs[0] & zargs[1]); +} + +void zadd(void) +{ + store(zargs[0] + zargs[1]); +} + +void zsub(void) +{ + store(zargs[0] - zargs[1]); +} + +void zmul(void) +{ + store(zargs[0] * zargs[1]); +} + +void zdiv(void) +{ + ZASSERT(zargs[1] != 0, "divide by zero"); + store((int16_t)zargs[0] / (int16_t)zargs[1]); +} + +void zmod(void) +{ + ZASSERT(zargs[1] != 0, "divide by zero"); + store((int16_t)zargs[0] % (int16_t)zargs[1]); +} + +void zlog_shift(void) +{ + int16_t places = zargs[1]; + + /* Shifting more than 15 bits is undefined (as of Standard 1.1), but + * do the most sensible thing. + */ + if(places < -15 || places > 15) + { + store(0); + return; + } + + if(places < 0) store(zargs[0] >> -places); + else store(zargs[0] << places); +} + +void zart_shift(void) +{ + int16_t number = zargs[0], places = zargs[1]; + + /* Shifting more than 15 bits is undefined (as of Standard 1.1), but + * do the most sensible thing. + */ + if(places < -15 || places > 15) + { + store(number < 0 ? -1 : 0); + return; + } + + /* Shifting a negative value in C has some consequences: + * • Shifting a negative value left is undefined. + * • Shifting a negative value right is implementation defined. + * + * Thus these are done by hand. The Z-machine requires a right-shift + * of a negative value to propagate the sign bit. This is easily + * accomplished by complementing the value (yielding a positive + * number), shifting it right (zero filling), and complementing again + * (flip the shifted-in zeroes to ones). + * + * For a left-shift, the result should presumably be the same as a + * logical shift, so do that. + */ + if(number < 0) + { + if(places < 0) store(~(~number >> -places)); + else store(zargs[0] << places); + } + else + { + if(places < 0) store(zargs[0] >> -places); + else store(zargs[0] << places); + } +}