123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- /* -*- c-file-style: "linux";indent-tabs-mode:t -*- */
- /* Copyright (C) 2017 Jeremiah Orians
- * Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org>
- * This file is part of mescc-tools
- *
- * mescc-tools is free software: 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.
- *
- * mescc-tools 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 mescc-tools. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "hex2_globals.h"
- unsigned shiftregister;
- unsigned tempword;
- int updates;
- void outOfRange(char* s, int value)
- {
- line_error();
- fputs("error: value ", stderr);
- fputs(int2str(value, 10, TRUE), stderr);
- fputs(" out of range for field type ", stderr);
- fputs(s, stderr);
- fputs("\n", stderr);
- exit(EXIT_FAILURE);
- }
- void UpdateShiftRegister(char ch, int value)
- {
- if ('.' == ch)
- {
- unsigned swap;
- /* Assume the user knows what they are doing */
- if(!BigEndian)
- {
- /* Swap from big-endian to little endian order */
- swap = (((value >> 24) & 0xFF) |
- ((value << 8) & 0xFF0000) |
- ((value >> 8) & 0xFF00) |
- ((value & 0xFF) << 24));
- }
- else
- {
- /* Big endian needs no change */
- swap = value;
- }
- /* we just take the 4 bytes after the . and shove in the shift register */
- swap = swap & ((0xFFFF << 16) | 0xFFFF);
- shiftregister = shiftregister ^ swap;
- }
- else if ('!' == ch)
- {
- /* Corresponds to RISC-V I format */
- /* Will need architecture specific logic if more architectures go this route */
- /* no range check because it needs to work with labels for lui/addi + AUIPC combos */
- /* !label is used in the second instruction of AUIPC combo but we want an offset from */
- /* the first instruction */
- value = value + 4;
- tempword = (value & 0xFFF) << 20;
- /* Update shift register */
- tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
- shiftregister = shiftregister ^ tempword;
- }
- else if ('@' == ch)
- {
- /* Corresponds to RISC-V B format (formerly known as SB) */
- /* Will need architecture specific logic if more architectures go this route */
- if ((value < -0x1000 || value > 0xFFF) || (value & 1)) outOfRange("B", value);
- /* Prepare the immediate's word */
- tempword = ((value & 0x1E) << 7)
- | ((value & 0x7E0) << (31 - 11))
- | ((value & 0x800) >> 4)
- | ((value & 0x1000) << (31 - 12));
- tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
- /* Update shift register */
- shiftregister = shiftregister ^ tempword;
- }
- else if ('$' == ch)
- {
- /* Corresponds with RISC-V J format (formerly known as UJ) */
- /* Will need architecture specific logic if more architectures go this route */
- if ((value < -0x100000 || value > 0xFFFFF) || (value & 1)) outOfRange("J", value);
- tempword = ((value & 0x7FE) << (30 - 10))
- | ((value & 0x800) << (20 - 11))
- | ((value & 0xFF000))
- | ((value & 0x100000) << (31 - 20));
- tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
- shiftregister = shiftregister ^ tempword;
- }
- else if ('~' == ch)
- {
- /* Corresponds with RISC-V U format */
- /* Will need architecture specific logic if more architectures go this route */
- if ((value & 0xFFF) < 0x800) tempword = value & (0xFFFFF << 12);
- else tempword = (value & (0xFFFFF << 12)) + 0x1000;
- tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
- shiftregister = shiftregister ^ tempword;
- }
- else
- {
- line_error();
- fputs("error: UpdateShiftRegister reached impossible case: ch=", stderr);
- fputc(ch, stderr);
- fputs("\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- void WordStorePointer(char ch, FILE* source_file)
- {
- /* Get string of pointer */
- ip = ip + 4;
- Clear_Scratch(scratch);
- int base_sep_p = consume_token(source_file);
- /* Lookup token */
- int target = GetTarget(scratch);
- int displacement;
- int base = ip;
- /* Change relative base address to :<base> */
- if ('>' == base_sep_p)
- {
- Clear_Scratch(scratch);
- consume_token (source_file);
- base = GetTarget (scratch);
- /* Force universality of behavior */
- displacement = (target - base);
- }
- else
- {
- displacement = Architectural_displacement(target, base);
- }
- /* output calculated difference */
- if('&' == ch) outputPointer(target, 4, TRUE); /* Deal with & */
- else if('%' == ch) outputPointer(displacement, 4, FALSE); /* Deal with % */
- else
- {
- line_error();
- fputs("error: WordStorePointer reached impossible case: ch=", stderr);
- fputc(ch, stderr);
- fputs("\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- unsigned sr_nextb()
- {
- unsigned rv = shiftregister & 0xff;
- shiftregister = shiftregister >> 8;
- return rv;
- }
- void DoByte(char c, FILE* source_file, int write, int update)
- {
- if(HEX == ByteMode)
- {
- if(0 <= hex(c, source_file))
- {
- if(toggle)
- {
- if(write) fputc(((hold * 16)) + hex(c, source_file) ^ sr_nextb(), output);
- ip = ip + 1;
- if(update)
- {
- hold = (hold * 16) + hex(c, source_file);
- tempword = (tempword << 8) ^ hold;
- updates = updates + 1;
- }
- hold = 0;
- }
- else
- {
- hold = hex(c, source_file);
- }
- toggle = !toggle;
- }
- }
- else if(OCTAL ==ByteMode)
- {
- if(0 <= octal(c, source_file))
- {
- if(2 == toggle)
- {
- if(write) fputc(((hold * 8)) + octal(c, source_file) ^ sr_nextb(), output);
- ip = ip + 1;
- if(update)
- {
- hold = ((hold * 8) + octal(c, source_file));
- tempword = (tempword << 8) ^ hold;
- updates = updates + 1;
- }
- hold = 0;
- toggle = 0;
- }
- else if(1 == toggle)
- {
- hold = ((hold * 8) + octal(c, source_file));
- toggle = 2;
- }
- else
- {
- hold = octal(c, source_file);
- toggle = 1;
- }
- }
- }
- else if(BINARY == ByteMode)
- {
- if(0 <= binary(c, source_file))
- {
- if(7 == toggle)
- {
- if(write) fputc((hold * 2) + binary(c, source_file) ^ sr_nextb(), output);
- ip = ip + 1;
- if(update)
- {
- hold = ((hold * 2) + binary(c, source_file));
- tempword = (tempword << 8) ^ hold;
- updates = updates + 1;
- }
- hold = 0;
- toggle = 0;
- }
- else
- {
- hold = ((hold * 2) + binary(c, source_file));
- toggle = toggle + 1;
- }
- }
- }
- }
- void WordFirstPass(struct input_files* input)
- {
- if(NULL == input) return;
- WordFirstPass(input->next);
- filename = input->filename;
- linenumber = 1;
- FILE* source_file = fopen(filename, "r");
- if(NULL == source_file)
- {
- fputs("The file: ", stderr);
- fputs(input->filename, stderr);
- fputs(" can not be opened!\n", stderr);
- exit(EXIT_FAILURE);
- }
- toggle = FALSE;
- int c;
- for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
- {
- /* Check for and deal with label */
- if(':' == c)
- {
- c = storeLabel(source_file, ip);
- }
- /* check for and deal with relative/absolute pointers to labels */
- if('.' == c)
- {
- /* Read architecture specific number of bytes for what is defined as a word */
- /* 4bytes in RISC-V's case */
- updates = 0;
- tempword = 0;
- while (updates < 4)
- {
- c = fgetc(source_file);
- DoByte(c, source_file, FALSE, TRUE);
- }
- ip = ip - 4;
- }
- else if(in_set(c, "!@$~"))
- {
- /* Don't update IP */
- c = Throwaway_token(source_file);
- }
- else if(in_set(c, "%&"))
- {
- ip = ip + 4;
- c = Throwaway_token(source_file);
- if ('>' == c)
- { /* deal with label>base */
- c = Throwaway_token(source_file);
- }
- }
- else if('<' == c)
- {
- pad_to_align(FALSE);
- }
- else if('^' == c)
- {
- /* Just ignore */
- continue;
- }
- else DoByte(c, source_file, FALSE, FALSE);
- }
- fclose(source_file);
- }
- void WordSecondPass(struct input_files* input)
- {
- shiftregister = 0;
- tempword = 0;
- if(NULL == input) return;
- WordSecondPass(input->next);
- filename = input->filename;
- linenumber = 1;
- FILE* source_file = fopen(filename, "r");
- /* Something that should never happen */
- if(NULL == source_file)
- {
- fputs("The file: ", stderr);
- fputs(input->filename, stderr);
- fputs(" can not be opened!\nWTF-pass2\n", stderr);
- exit(EXIT_FAILURE);
- }
- toggle = FALSE;
- hold = 0;
- int c;
- for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
- {
- if(':' == c) c = Throwaway_token(source_file); /* Deal with : */
- else if('.' == c)
- {
- /* Read architecture specific number of bytes for what is defined as a word */
- /* 4bytes in RISC-V's case */
- updates = 0;
- tempword = 0;
- while (updates < 4)
- {
- c = fgetc(source_file);
- DoByte(c, source_file, FALSE, TRUE);
- }
- UpdateShiftRegister('.', tempword);
- ip = ip - 4;
- }
- else if(in_set(c, "%&")) WordStorePointer(c, source_file); /* Deal with % and & */
- else if(in_set(c, "!@$~"))
- {
- Clear_Scratch(scratch);
- consume_token(source_file);
- UpdateShiftRegister(c, Architectural_displacement(GetTarget(scratch), ip)); /* Play with shift register */
- }
- else if('<' == c) pad_to_align(TRUE);
- else if('^' == c) ALIGNED = TRUE;
- else DoByte(c, source_file, TRUE, FALSE);
- }
- fclose(source_file);
- }
|