program for interpretation of a simple instruction set - c

I have a problem I need to solve and I have no freaking idea how to do it. If someone would be willing to help I would very much appreciate it. I know I'm asking for a lot, but I really need it.
Create a program for interpretation of a simple instruction set consisting of the instructions: MVI, MOV, AND, OR, NOT, LESS, LEQ, GRE, GEQ, JMP, PRN, SUM, SUB, PRB, SL and SR, described in this document. Your task is to make a program that takes as an input a binary representation of a list of instructions, and as an output it prints the corresponding result (after the execution of the instructions). The input can contain all the instructions except SUB and PRB that you do not have to implement. Conversion from binary system to any other numeral system should not be made, except at the moment when you need to find the line that should be executed next when the condition is satisfied (GRE, GEQ, LESS, LEQ, JMP), but the comparison of the numbers in the condition should be made based on the binary representatio/pn. All data are represented in SM binary system. There are eight 16-bit registers available enumerated from 0 to 7.
#include<stdio.h>
#define MAX 1000
char registers[8][16];
void MVI(int reg, char *value) {
// code here
}
void MOV(int reg1, int reg2) {
// code here
}
void AND(int reg1, int reg2, int reg3) {
// code here
}
void OR(int reg1, int reg2, int reg3) {
// code here
}
void NOT(int reg1, int reg2) {
// code here
}
void PRN(int reg) {
// code here
}
void SUM(int reg1, int reg2, int reg3) {
// code here
}
void SL(int reg) {
// code here
}
void SR(int reg) {
// code here
}
int main() {
int i,j,k;
int N = 0; // number of lines in the input
char c;
char lines[MAX][16];
while (1) {
scanf("%c", &c);
if (c == '\n') {
break;
}
lines[N][0] = c;
for (i=1;i<16;i++) {
scanf("%c", &lines[N][i]);
}
N++;
scanf("%c", &c);
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 16; j++) {
registers[i][j] = '0';
}
}
// code here
return 0;
}

I think the big piece you need is dispatching the functions based on the source line. There are a number of ways you can do this, but a useful piece for all of them is strstr(a,b)==a which will check if the string a begins with the contents of the string b.
You can do a chain of if-else blocks.
if (strstr(line[i], "SUM")==line[i]){
SUM(...);
} else if (strstr(line[i], "AND")==line[i]) {
AND(...);
}
Or you can precompile the user program by scanning for the opcodes when you read the source and store them as single-byte small codes. You would want the uppercase identifiers to be enum values, and use the lowercase versions for the function names. Then the chain is simpler.
if (line[i][0] == SUM) {
SUM(...);
} else if (line[i][0] == AND) {
AND(...);
}
But, with small integer codes, there are even better ways. A switch.
switch(line[i][0]){
case SUM: sum(...); break;
case AND: and(...); break;
}
A function table. But this is where you have be clever. A function must always be called with arguments of the correct type, but function-pointers allow you to bypass the compiler's ability
to check that this is so. So for this method, all functions should have the same arguments since
they are all called by a single function-call line.
void (*optab[])(...) = { sum, and, ... };
optab[ line[i][0] ](...); // calls sum() or and() by using the opcode in the array lookup

Related

Optimization with interrupts or threads and global variables

I find that I have some difficulty with how to best write communication between functions that are out of the normal flow of code. A simple example is:
int a = 0;
volatile int v = 0;
void __attribute__((used)) interrupt() {
a++;
v++;
}
int main() {
while(1) {
// asm("nop");
a--;
v--;
if (v > 10 && a > 10)
break;
}
return 0;
}
It is not surprising that the main while loop can optimize the a variable to a register and thus never see any changes from the interrupt. If the variable is volatile then it is annoying in that every time it is used in needs to be reread from or rewritten to memory. And in that technique any communication variable across threads would need to be volatile. A synchronization primitive (or even the commented out "nop") solves the problem because it seemingly has a side effect to create a compiler barrier. But if I understand correctly that would mean flushing the entire state of all the registers used in main, where maybe it's less harsh to just have a few variables as volatile. I currently use the two techniques but I wish I had a more standard method for dealing with the issue. Can anyone comment on best strategies here?
A link to some assembly
So you want a means of reducing the number of times a is looked up. The following reduces it to once a loop:
volatile int a = 0;
volatile int v = 0;
void __attribute__((used)) interrupt() {
a++;
v++;
}
int main() {
while(1) {
int b = --a;
--v;
if (v > 10 && b > 10)
break;
}
return 0;
}
Nothing stops you from checking even less often similarly.

"$MCLR$ is low. Processor is in reset." Error on Pic18

On this circuit and code, I tried to make a counter that when no one pass through (for example it is a passage at the metro station), there will read 1 value at RC7 lead of the processor. If someone pass through the signal change to 0. And program will count the how many people pass away over there and show the number of people on the 7-Segment LCD until 10. When 10 people pass through of the passage, the LED (D1) will be blinking for 1 seconds.
I tried to write a code about this algorithm, and when I load it to Pic18F45K22 but, it is not working. Proteus show error message like,
[PIC18] PC=0x0000. $MCLR$ is low. Processor is in reset. [U1]
The circuit that I designed given at below Figure 1:
The solutions that I tried:
I used pull-up resistors. It did not work.
We describe the frequency value in Micro C code. It did not work.
And the algorithm given at below:
#include <xc.h>
#define _XTAL_FREQ 4000000
unsigned char x=0;
void MSDelay(unsigned int);
void main()
{
TRISC=0xff;
TRISA=0x00;
while(1)
{
if (PORTC==0)
{
x++;
MSDelay(200);
}
if (x==1)
{
PORTA==0x3f;
}
if (x==2)
{
PORTA==0x06;
}
if (x==3)
{
PORTA==0x5b;
}
if (x==4)
{
PORTA==0x4f;
}
if (x==5)
{
PORTA==0x66;
}
if (x==6)
{
PORTA==0x6d;
}
}
}
void MSDelay(unsigned int itime){ //for delay
unsigned int i;
unsigned int j;
for(i=0;i<itime;i++){
for(j=0;j<165;j++){
}
}
}
So I make the answer for you:
The error ist here:
if (x==1)
{
PORTA==0x3f;
}
If you want assign a value you need = and not ==
if (x==1)
{
PORTA=0x3f;
}

How to break up C-Functions without increasing stacksize

Working in embedded Systems design, I am often confronted with Legacy Code, where somebody wrote some ISR which consists of a huge if/else-Jungle, sometimes spanning multiple screen-lengths. Now, trying to be a good programmer I try to refactor the function, using the paradigms I learned, one of them being: "A function should do one thing only".
So I break down the function into multiple static sub-function, which have descriptive names and encapsulate variables. But since I am working on an embedded device, I need to be considerate of stacksize and the number of jumps (especially in an ISR that might get called often and might itself get interrupted by something else).
Now, of cause most(or even all) Compilers can be forced to inline a function (as __always_inline does with gcc). But even that increases stacksize, if I have to pass parameters (they do not necessarily get optimized away), even if it is just a few bytes per parameter.
Now for my actual question: Is there a way not to increase stacksize while breaking up functions in C?
EDIT:
To make my Question clearer: Here is an Example of some Code, where I just shifted some of the code to inline-functions.
Static stack usage is 144 without inline-functions and 160 with inline functions.
Original:
#include <stdio.h>
#include <string.h>
int main(){
char inputString[100];
scanf("%s",inputString);
static char delimiterArray[] = {' ','+','-','/','*','='};
for(int i = 0; i<sizeof(inputString); i++){
printf("%c",inputString[i]);
char* inputChar = inputString + i;
for(int j = 0; j<sizeof(delimiterArray);j++){
if( *inputChar == delimiterArray[j]){
printf("DELIMITER: %c",delimiterArray[j]);
}
if(inputString[i] == '\0'){
printf("\nNuberOfChars: %d\n",i);
break;
}
}
}
return 0;
}
With inline-functions:
#include <stdio.h>
#include <string.h>
static inline void checkForDelimiters(char* inputChar)__attribute__((always_inline));
static inline void decomposeString(char* inputString)__attribute__((always_inline));
int main(){
char inputString[100];
scanf("%s",inputString);
decomposeString(inputString);
return 0;
}
static void checkForDelimiters(char* inputChar){
static char delimiterArray[] = {' ','+','-','/','*','='};
for(int j = 0; j<sizeof(delimiterArray);j++){
if(*inputChar == delimiterArray[j]){
printf("DELIMITER: %c",delimiterArray[j]);
}
}
}
static void decomposeString(char* inputString){
for(int i = 0; i<sizeof(inputString); i++){
printf("%c",inputString[i]);
checkForDelimiters(inputString+i);
if(inputString[i] == '\0'){
printf("\nNuberOfChars: %d\n",i);
break;
}
}
}

Can't extract an integer from a thermometer byte reading

Afternoon all,
Apologies if this question is in the wrong format or in the wrong place, if this is the case, please flag and I'll change it or take it elsewhere.
I am using a development board to send a temperature reading to an LCD panel and I am really struggling to comprehend as to why the temperature at the moment that the program is run isn't being printed onto my LCD. A lot of the code is from framework given to me and is correct as far as I can tell.
My question stems from these functions:
uch get_temp()
{
int i;
DQ_HIGH();
reset(); //reset,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0X44); //send temperature convert command
for(i=20;i>0;i--)
{
//display(); //call some display function,insure the time of convert temperature
}
reset(); //reset again,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0XBE); //send read temperature command
TLV=read_byte(); //read temperature low byte
THV=read_byte(); //read temperature high byte
DQ_HIGH(); //release general line
TZ=(TLV>>4)|(THV<<4)&0X3f; //temperature integer
TX=TLV<<4; //temperature decimal
if(TZ>100)
{
TZ/100;
} //not display hundred bit
ge=TZ%10; //integer Entries bit
shi=TZ/10; //integer ten bit
wd=0;
if (TX & 0x80)
wd=wd+5000;
if (TX & 0x40)
wd=wd+2500;
if (TX & 0x20)
wd=wd+1250;
if (TX & 0x10)
wd=wd+625; //hereinbefore four instructions are turn decimal into BCD code
shifen=wd/1000; //ten cent bit
baifen=(wd%1000)/100; //hundred cent bit
qianfen=(wd%100)/10; //thousand cent bit
wanfen=wd%10; //myriad cent bit
NOP();
return TZ;
}
I have modified this function so that it should return the temperature integer (unsigned char TZ)
This function is then called here:
void Init_lcd(void)
{
ADCON1 = 0x07; //required setting of analog to digital
uch Temp;
TRISD = 0x00;
TRISA1 = 0;
TRISA2 = 0;
TRISA3 = 0;
writeCommand(0x0f);
writeCommand(0x38); //set to two line mode
clearDisplay();
writeString("MAIN MENU");
Temp = get_temp();
writeString(Temp);
writeCommand(0xC0); //change cursor line
}
It isn't printing anything after "MAIN MENU", which obviously means I'm doing something wrong. I can provide further clarification/code on request.
I should probably mention that I am NOT only simply looking for an answer of "paste this in and it'll work". Any feedback in which I understand my mistake and how to fix it is greatly appreciated.
Thanks in advance!
EDIT:
A few people are asking about my writing functions so for further clarification I'll paste them here:
void writeChar(unsigned char ch)
{
lcd = ch;
RS = 1;
RW =0;
E = 1;
lcdDelay();
E=0;
}
void writeString(char *stringToLcd)
{
while(*stringToLcd > 0)
{
writeChar(*stringToLcd++);
}
}
Temp is an unsigned char
uch Temp;
//...
Temp = get_temp();
writeString(Temp);
So, using writeString() will produce undefined results.
You should use write() instead (depending on the library you're using).
But you probably want to convert the return value of get_temp() to an ASCII string first, and display that using writeString().
Update:
void writeString(char *stringToLcd)
This function needs a char*, so you can't provide a single uch.
You need to convert Temp to a string first, using itoa() for example.
I could suggest you to implement a new function
void writeUCH(uch value)
{
unsigned char test = (value >= 100) ? 100 : (value >= 10) ? 10 : 1;
while(test > 0)
{
writeChar((value/test)+'0');
value = value%test;
test /= 10;
}
}
this line:
TZ/100;
will result in no change to TZ
what you really want is this:
TZ = TZ%100;
the value returned from get_temp() is an integer, not a ascii string. I would expect the LCD needs ascii characters, not the binary value of the bytes of an int variable.

c - Avoid if in loop

Context
Debian 64.
Core 2 duo.
Fiddling with a loop. I came with different variations of the same loop but I would like to avoid conditional branching if possible.
But, even if I think it will be difficult to beat.
I thought about SSE or bit shifting but still, it would require a jump (look at the computed goto below). Spoiler : a computed jump doesn't seems to be the way to go.
The code is compiled without PGO. Because on this piece of code, it makes the code slower..
flags :
gcc -march=native -O3 -std=c11 test_comp.c
Unrolling the loop didn't help here..
63 in ascii is '?'.
The printf is here to force the code to execute. Nothing more.
My need :
A logic to avoid the condition. I assume this as a challenge to make my holydays :)
The code :
Test with the sentence. The character '?' is guaranteed to be there but at a random position.
hjkjhqsjhdjshnbcvvyzayuazeioufdhkjbvcxmlkdqijebdvyxjgqddsyduge?iorfe
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv){
/* This is quite slow. Average actually.
Executes in 369,041 cycles here (cachegrind) */
for (int x = 0; x < 100; ++x){
if (argv[1][x] == 63){
printf("%d\n",x);
break;
}
}
/* This is the slowest.
Executes in 370,385 cycles here (cachegrind) */
register unsigned int i = 0;
static void * restrict table[] = {&&keep,&&end};
keep:
++i;
goto *table[(argv[1][i-1] == 63)];
end:
printf("i = %d",i-1);
/* This is slower. Because of the calculation..
Executes in 369,109 cycles here (cachegrind) */
for (int x = 100; ; --x){
if (argv[1][100 - x ] == 63){printf("%d\n",100-x);break;}
}
return 0;
}
Question
Is there a way to make it faster, avoiding the branch maybe ?
The branch miss is huge with 11.3% (cachegrind with --branch-sim=yes).
I cannot think it is the best one can achieve.
If some of you manage assembly with enough talent, please come in.
Assuming you have a buffer of well know size being able to hold the maximum amount of chars to test against, like
char buffer[100];
make it one byte larger
char buffer[100 + 1];
then fill it with the sequence to test against
read(fileno(stdin), buffer, 100);
and put your test-char '?' at the very end
buffer[100] = '?';
This allows you for a loop with only one test condition:
size_t i = 0;
while ('?' != buffer[i])
{
++i;
}
if (100 == i)
{
/* test failed */
}
else
{
/* test passed for i */
}
All other optimisation leave to the compiler.
However I couldn't resist, so here's a possible approach to do micro optimisation
char buffer[100 + 1];
read(fileno(stdin), buffer, 100);
buffer[100] = '?';
char * p = buffer;
while ('?' != *p)
{
++p;
}
if ((p - buffer) == 100)
{
/* test failed */
}
else
{
/* test passed for (p - buffer) */
}

Resources