- NOTE: This is
not the final version of my Bitmap Smoother ASIC.
- I
will post the final version in the future.
--file addivider_beh.VHD.
--The input to this program is an ASCII file, and its name is in.bmp.
--It must exist in the same directory as this source code.
--The name of the output file is out.txt.
--The input and output format follows this format:
--The header consists of the first 4 rows:
--BM reserved word
--00 reserved
--rows
--cols
--The pixels grey levels follow the header. Each line contains one row
--of pixels, and each byte(two characters) represent the gray level of a pixel.
--For example:
--BM
--00
--20
--20
--FFAA009BCDEF0707096600011111000101010101
--1111000100111111000101001111001111000100
--11110001011011110
library std;
use std.textio.all;
package declarations is
constant dbus:integer:=8;--dbus stands for data bus
constant col_adres_bus:integer:=12;
constant col_ram_size:integer:=100 constant maxrow:bit_vector:="10";
--The biggest picture can have 99 cols. Therefore the max RAM col
--size needed is 101.
subtype data is bit_vector(dbus downto 1);
type RAM is array (0 to 2,0 to col_ram_size) of data;
constant dbus2:integer:=dbus+2;
constant dbus3:integer:=dbus+3;
subtype data2 is bit_vector(dbus2 downto 1);
subtype data3 is bit_vector(dbus3 downto 1);
subtype col_adres is bit_vector(1 to col_adres_bus);
subtype row_adres is bit_vector(1 to 2);
type hex is ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
--redefine if lower case letters are desired
function add2(a,b:bit_vector) return bit_vector;
function char2hex(inchar:character) return hex;
function hex2char(inchar:hex) return character;
function increment(val:bit_vector;upper_limit:bit_vector) return bit_vector;
procedure int2bv(coming:in integer;leaving:inout bit_vector);
function bv2int(coming:in bit_vector) return integer;
end declarations;
package body declarations is
--Note:In a procedure or function I can have signals as parameters. If no type is specified
--then variable is the default.
function add2(a,b:bit_vector) return bit_vector is
--This function accepts two 10-bit binary numbers and outputs their sum (11-bits).
variable vsum:bit_vector(dbus3 downto 1);
variable carry:bit:='0';
begin
for i in 1 to dbus2 loop
vsum(i):=(a(i) xor b(i)) xor carry;
carry:=(a(i) and b(i)) or (carry and (a(i) or b(i)));
end loop;
vsum(dbus3):=carry;
return vsum;
end add2;
function char2hex(inchar:character) return hex is
variable x:integer;
begin
case inchar is
when '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => x:=character'pos(inchar)-character'pos('0');
when 'A'|'B'|'C'|'D'|'E'|'F' => x:=character'pos(inchar) - 55;
when others => x := 0;--return 0h when invalid character
end case;
return hex'val(x);
end;
function hex2char(inchar:hex) return character is
variable x:integer;
begin
case inchar is
when '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => x:=hex'pos(inchar)+48;
when 'A'|'B'|'C'|'D'|'E'|'F' => x:=hex'pos(inchar) + 55;
when others => x := 48;--return '0' when invalid character
end case;
return character'val(x);
end;
function increment(val:bit_vector;upper_limit:bit_vector) return bit_vector is
alias input:bit_vector(val'length downto 1) is val;
variable result:bit_vector(input'range):=input;
variable carry:bit:='1';
begin
if (val=upper_limit)
then result:=(others=>'0');
else for i in input'low to input'high loop
result(i) := input(i) xor carry;
carry := input(i) and carry;
exit when carry = '0';
end loop;
end if;
return result;
end increment;
procedure int2bv(coming:in integer;leaving:inout bit_vector) is
variable bv : bit_vector(leaving'length downto 1) := (others => '0');
variable pos : integer := 0;
variable tmpval : integer := coming;
begin
for i in 1 to leaving'length loop
pos := pos + 1;
if (tmpval mod 2) = 1 then bv(i) := '1';
end if;
tmpval := tmpval / 2;
exit when tmpval = 0;
end loop;
leaving:=bv;
end;
function bv2int(coming:in bit_vector) return integer is
--conversion of array of logic values (bit vector) to an integer
variable work:integer:=0;
begin
for i in coming'range loop
work:=work*2;
if coming(i)='1' then work:=work+1; end if;
end loop;
return work;
end bv2int;
end declarations;
use work.declarations.all;
package chips is
component cadd2 port(ac,bc:bit_vector;sum2:out bit_vector); end component;
end chips;
use work.declarations.all;
entity cadd2 is port(ac,bc:bit_vector;sum2:out bit_vector); end cadd2;
architecture structural of cadd2 is
begin
a2:process(ac,bc)
--This component accepts two 10-bit binary numbers and outputs their sum (11-bits).
variable vsum:bit_vector(dbus3 downto 1);
variable carry:bit:='0';
begin
for i in 1 to dbus2 loop
vsum(i):=(ac(i) xor bc(i)) xor carry;
carry:=(ac(i) and bc(i)) or (carry and (ac(i) or bc(i)));
end loop;
vsum(dbus3):=carry;
sum2 <= vsum;
end process;
end structural;
entity cmod is port(acm,bcm:integer;cmodo:out integer); end cmod;
use work.declarations.all;
entity main_body is
end;
library std;
use std.textio.all;
architecture behavioral of main_body is
signal getpel:bit:='1';--must be 1. Do not change
signal bitCLK:bit:='0';
signal bitCLKcycle:bit_vector(1 to 4):="0000";
signal zreadallowed:boolean:=true;
signal zdone:boolean;
signal No_read:data:=(others => '0');
signal No1,No2,No3,No4,No5,div8,div16,div64:data2:=(others => '0');
signal res,sum2,sum3,sum4,sum5,semires:data3;
signal rdbytectr:integer:=-1;
signal rdlinectr,wrbytectr,wrlinectr:integer:=0;--wrmodcols=wrbyte mod cols
-- signal p2c,f3rc:col_adres := (others => '0');
-- signal p4c:col_adres := "000000000001";
-- signal frontr,p234r,:row_adres:="00";
-- signal rearr:row_adres:="00";--insert data into RAM at (rearr,f3rc)
component cadd2 port(ac,bc:bit_vector;sum2:out bit_vector); end component;
for csum2,csum3,csum4,csum5 : cadd2 use entity work.cadd2(structural);
file inf:text is "in.bmp";
file outf:text is out "out.txt";
file troublee:text is out "trouble.txt";
procedure write_string(l:inout line;value:in string;justified:in side:=right;field:in width:=0) is
begin write(l,value,justified,field);end;
begin
csum2: cadd2 port map (No1,No2,sum2);
csum3: cadd2 port map (sum2(dbus2 downto 1),No3,sum3);
csum4: cadd2 port map (sum3(dbus2 downto 1),No4,sum4);
csum5: cadd2 port map (sum4(dbus2 downto 1),No5,sum5);
-- cdiva: cadd2 port map (div8,div16,semires);
-- cavg5: cadd2 port map (semires(dbus2 downto 1),div64,res);
readbmp:process(getpel,bitCLK)
variable eol:boolean;
variable za2,zb2:data2;
variable zres:data3;
variable zhibyte,zNo,zrows,zcols:natural;
variable zin,zout:line;
variable mem:RAM;
variable byte:string(1 to 2);
variable zpelbyte:hex;
variable zmaxcol:col_adres;
variable p2c,f3rc:col_adres := (others => '0');
variable p4c:col_adres := "000000000001";
variable frontr,p234r,rearr:row_adres:="00";
--insert data into RAM at (rearr,f3rc)
begin
if getpel = '1' and bitCLK = '0' and rdbytectr<0
then --reading the header
readline(inf,zin);writeline(outf,zin);--BM
readline(inf,zin);writeline(outf,zin);--00
readline(inf,zin);read(zin,zcols,eol);write(zin,zcols);writeline(outf,zin);
int2bv(zcols-1,zmaxcol);
readline(inf,zin);read(zin,zrows,eol);write(zin,zrows);writeline(outf,zin);
rdbytectr<=0;
--processing the pixels
elsif getpel = '1' and bitCLK = '1' and not zdone
then if wrbytectr > 1 and (wrbytectr mod zcols) = 0
then p234r:=increment(p234r,maxrow);
writeline(outf,zout);--flush before eof
wrlinectr<=wrlinectr+1;
end if;
if wrlinectr > 0 and (wrbytectr mod zcols) = 0
--skipping increasing first row, because of first row mirroring
then frontr:=increment(frontr,maxrow);
end if;
p4c:=increment(p4c,zmaxcol);
p2c:=increment(p2c,zmaxcol);
if (wrbytectr mod zcols) = 0 --don't touch
then p4c := "000000000001";--no need to modify f3rc
p2c := (others => '0');--mirroring 1st column
elsif (wrbytectr mod zcols) = 1
then p2c := (others => '0');--rewinding 1st column
elsif (wrbytectr mod zcols) = zcols - 1 -- right edge mirroring
then p4c := zmaxcol;--no need to modify other col pointers
end if;
if (rdbytectr mod zcols) = 0 and rdbytectr < zrows*zcols
then readline(inf,zin);
rdlinectr<=rdlinectr+1;
end if;
if rdbytectr > 1 and (rdbytectr mod zcols) = 0
then rearr:=increment(rearr,maxrow);
end if;
if rdbytectr>0
then f3rc:=increment(f3rc,zmaxcol);
end if;
--The following algorithm is used:
--read inc ctrs, read inc ctrs,read
--inc ctrs,read,avg5 inc ctrs,read,avg5......
if rdbytectr < zrows*zcols
then read(zin,byte,eol);
zhibyte:=hex'pos(char2hex(byte(1)));
zNo:=hex'pos(char2hex(byte(2)));--low byte
zNo:=16*zhibyte + zNo;--grey level in decimal
int2bv(zNo,za2);
No_read<=za2(dbus downto 1);
mem(bv2int(rearr),bv2int(f3rc)):=za2(dbus downto 1);
end if;
rdbytectr<=rdbytectr+1;
bitCLKcycle<="0001";
elsif getpel = '0' and bitCLK = '0' and rdbytectr > 1 and not zdone
then case bitCLKcycle is
when "0011"=>if wrbytectr>zrows*zcols then zdone<=true;
end if;
when "1000"=>if rdbytectr=zrows*zcols then zreadallowed<=false;
end if;
when others=>null;
end case;
elsif getpel = '0' and bitCLK = '1' and not zdone
then
if rdbytectr > zcols --don't touch
then
case bitCLKcycle is --add numbers
when "0010"=>No1<="00" & mem(bv2int(frontr),bv2int(f3rc));
No2<="00" & mem(bv2int(p234r),bv2int(p2c));
--& = concatenation
--extend 8 bit signals to 10 bits
when "0011"=>No3<="00" & mem(bv2int(p234r),bv2int(f3rc));
when "0100"=>No4<="00" & mem(bv2int(p234r),bv2int(p4c));
when "0101"=>No5<="00" & mem(bv2int(rearr),bv2int(f3rc));
--za2:="00" & mem(bv2int(rearr),bv2int(f3rc));
-- No5<=za2;
-- sum5<=add2(za2,sum4(dbus2 downto 1));
when "0110"=>za2:="00" & sum5(dbus3 downto 4);--divide by 8
zb2:="000" & sum5(dbus3 downto 5);--divide by 16
div64<="00000" & sum5(dbus3 downto 7);--divide by 64
div8<=za2;
div16<=zb2;
semires<=add2(za2,zb2);
when "0111"=>zres:=add2(semires(dbus2 downto 1),div64);
res<=zres;
--FLUSHING JUST PROCESSED BYTE
zNo:=bv2int(zres);
zpelbyte:=hex'val(zNo/16);
byte(1):=hex2char(zpelbyte);
zpelbyte:=hex'val(zNo mod 16);
byte(2):=hex2char(zpelbyte);
write(zout,byte);
wrbytectr <= wrbytectr + 1;
when others=>null;
end case;
end if;
bitCLKcycle<=increment(bitCLKcycle,"1000");
end if;--header or pixels
end process;
end behavioral;