%=============================================== % Hamblen chapter 9: assembler--- text to Altera MIF file %=============================================== % Bruce Land -- Cornell University -- July 2008 %=============================================== % input format: % define % symbol1 value1 % symbol2 value2 % ... % data 200 (starting address, decimal) % name1 length1 value1(s) % name2 length2 value2(s) % ... %code (always starts at 0) % label1: opcode1 addr1 ;comment % opcode2 addr2 ;comment % ; comment % 'addr' can be 'name' or 'symbol' %=============================================== clear all %query for *.asm file [fname,fpath] = uigetfile('*.asm') ; fid = fopen ([fpath,fname]); % init state state==1 implies define; ==2 implies data; ==3 implies code state = 0; % init definition count nDef = 0; % init data count nData = 0; % init code count nCodeLine = 0; % init assembler opcode string/value pairs nOpcode = 9 ; opcode{1,1} = 'add'; opcode{1,2} =0; opcode{2,1} = 'store'; opcode{2,2} =1; opcode{3,1} = 'load'; opcode{3,2} =2; opcode{4,1} = 'jump'; opcode{4,2} =3; opcode{5,1} = 'jneg'; opcode{5,2} =4; opcode{6,1} = 'out'; opcode{6,2} =5; opcode{7,1} = 'in'; opcode{7,2} =6; opcode{8,1} = 'mult'; opcode{8,2} =7; opcode{9,1} = 'shl'; opcode{9,2} =8; %=============================================== % Tokenize the input file: % skip blank lines, ignore comments % build tables of definitions, data, code while feof(fid) == 0 %are we done reading the file yet? txtline = fgetl(fid); %get one line % trim off semicolons and comments % If line starts with ';' get next line semicolPos = strfind(txtline, ';'); if (~isempty(semicolPos)) if (semicolPos(1)>1) txtline = txtline(1:semicolPos(1)-1) ; else continue % whole line is a comment -- get next line end end % get first token of the line, look for state changes % and trim blank lines [token,rtxt] = strtok(txtline) ; if (strcmp(token, 'define')) state = 1; continue % get the next line elseif (strcmp(token, 'data')) state = 2; addrData = str2num(strtok(rtxt)) ; %data section line has an address on it continue % get the next line elseif (strcmp(token, 'code')) state = 3; continue % get the next line elseif (isempty(token)) continue % line was blank end %'define' state machine: build a table of definitions name,value if (state==1) nDef = nDef + 1; def{nDef,1} = token ; def{nDef,2} = strtok(rtxt) ; end %'data' state machine: build a table of data name,location if (state==2) nData= nData + 1; data{nData,1} = token ; % mem location name [token,rtxt] = strtok(rtxt) ; % get count data{nData,2} = str2num(token) ; for i = 1:data{nData,2} [token,rtxt] = strtok(rtxt) ; %get value if (~isempty(token)) data{nData,2+i} = token ; %str2num(token) ; else data{nData,2+i} = 0 ; end end end %'code' state machine: build a table of lines of code % builds a table of labels, opcodes, and addresses if (state==3) nCodeLine= nCodeLine + 1; % handle label if (~isempty(strfind(token, ':'))) %label? CodeLine{nCodeLine,1} = token(1:end-1) ; %strip off colon and store [token,rtxt] = strtok(rtxt) ; %get opcode end % process opcode or null, and if opcode get address if (~isempty(token)) CodeLine{nCodeLine,2} = lower(token) ; % store opcode in lowercase [token,rtxt] = strtok(rtxt) ; %get address CodeLine{nCodeLine,3} = token ; % store address else continue % get next line end end %end of 'code' state machine end fclose(fid); % done reading asm file %=============================================== %start generating mif file (object code generation) fid = fopen([fpath,fname(1:end-4),'.mif'], 'w') ; fprintf(fid, '%s\n', 'DEPTH = 256;') ; fprintf(fid, '%s\n', 'WIDTH = 18;'); fprintf(fid, '%s\n', ' '); fprintf(fid, '%s\n', 'ADDRESS_RADIX = HEX;'); fprintf(fid, '%s\n', 'DATA_RADIX = HEX;'); fprintf(fid, '%s\n', ' '); fprintf(fid, '%s\n', 'CONTENT'); fprintf(fid, '%s\n', 'BEGIN'); fprintf(fid, '%s\t:\t%s\n', '[00..FF]', '00000;'); % generate code section in mif format for i=1:nCodeLine hexaddr = i - 1; %zero based addresses for code %opcode table lookup: find the hex opcode which matches the % current line's string opcode instOpcode = nan ; for j=1:nOpcode if (strcmp(opcode{j,1}, CodeLine{i,2})) instOpcode = opcode{j, 2} ; end end if (isnan(instOpcode)) error(['Bad opcode in code line:', num2str(i)]) end % convert address symbol into a number instAddr % if a number, use it % if opcode is a 'jump', 'jneg' use labels % of opcode is an 'out' or 'in'use defines % otherwise use data names instaddr = nan ; % check for numeric if (~isempty(str2num(CodeLine{i,3}))) instaddr = str2num(CodeLine{i,3}) ; % label search elseif (strcmp(CodeLine{i,2}, 'jump') | strcmp(CodeLine{i,2}, 'jneg')) for j=1:nCodeLine %search label table if (strcmp(CodeLine{i,3}, CodeLine{j,1})) instaddr = j-1 end end % 'define' search elseif (strcmp(CodeLine{i,2}, 'out') | strcmp(CodeLine{i,2}, 'in')) for j=1:nDef %search label table if (strcmp(CodeLine{i,3}, def{j,1})) instaddr = str2num(def{j,2}) ; end end else % search data names instaddr = addrData ; %init to beginning of data table for j=1:nData %search label table if (strcmp(CodeLine{i,3}, data{j,1})) break end instaddr = instaddr + data{j,2} ; end end %end addr search %check for undefined address if (isnan(instaddr)) error(['Bad address in code line:', num2str(i)]) end %build the hex instruction 12-bits of address 2^12=2046 inst = 4096*instOpcode + instaddr ; fprintf(fid, '%02x\t:\t%05x;\t%% %s: %s %s %% \n', ... hexaddr, inst, CodeLine{i,1}, CodeLine{i,2}, CodeLine{i,3}) end % generate data section in mif format hexaddr = addrData ; %init address to beginning of data section for i=1:nData for j=1:data{i,2} if (~isempty(data{i,2+j})) datavalue = data{i,2+j} ; else datavalue = 0; end fprintf(fid, '%02x\t:\t%s;\t%% %s %% \n', hexaddr, datavalue, data{i,1} ) hexaddr = hexaddr + 1; end end fprintf(fid, '%s\n', 'END ; ') fclose(fid) % Altera MIF format example % DEPTH = 256; % Memory depth and width are required % % WIDTH = 16; % Enter a decimal number % % % ADDRESS_RADIX = HEX; % Address and value radixes are optional % % DATA_RADIX = HEX; % Enter BIN, DEC, HEX, or OCT; unless % % % otherwise specified, radixes = HEX % % -- Specify values for addresses, which can be single address or range % -- program adds one to a counter, MEM(12), every time A overflows to neg value % CONTENT % BEGIN % [00..FF] : 0000; % Range--Every address from 00 to FF = 0000 (Default) % % 00 : 0210; % LOAD A with MEM(10) -- clear A% % 01 : 0011; % ADD MEM(11) to A -- increment A% % 02 : 0404; % JNEG to 04 -- skip next instruction if A is negative% % 03 : 0301; % JMP to 01 -- increment A if it is still positive% % 04 : 0212; % LOAD A from MEM(12) -- get output counter% % 05 : 0011; % ADD MEM(11) to A -- incrment output counter% % 06 : 0500; % OUTPUT A % % 07 : 0112; % STORE A to MEM(12) -- save it% % 08 : 0300; % JUMP to 00 (loop forever) -- reset A % % 10 : 0000; % initial A Value % % 11 : 0001; % increment for A and output value % % 12 : 0000; % output value % % END ;