⬆️ ⬇️

Making an IBM PC on FPGA

I think many who worked with the FPGA thought - and not to make your computer completely on it, with the x86 processor, peripherals, and so on? 8-bit computers are often implemented in FPGA, but here is a whole PC ...



In addition to the x86 processor, you need a BIOS with all the interrupts implemented (including access to the “disk” on the SD card), a BIOS of a VGA-compatible video card, all peripherals, a memory controller, a timer, and much more. The task is much more complicated than it seems at first glance, but nevertheless, it is solved in the ZetCPU project.



Of the restrictions, only the 16-bit mode at 12.5Mhz works, without a math coprocessor.

')

Iron



To run, we need a debug board with FPGA. I really liked the board Terasic DE2-115 (on Altera Cyclone IV with 115 thousand. LE). The student price is $ 299, less than the retail price of a single chip.



The board has a lot of built-in hardware - 2 x 8 MB of SDRAM memory, 256KB of SRAM, 1 MB of flash memory, 2 PHY 1Gb Ethernet, VideoDAC for connecting to VGA, LEDs / switches / buttons, a connector for an SD card, and so on. But this project uses far from everything (only SD card, Flash, SDRAM and VideoDAC).



The project can also be launched on DE0 Nano with a student price of $ 59, but only text mode will work there.



Run



There are several obvious points in the installation that are not described in the instructions :







Now you can connect a monitor to the board, a PS / 2 keyboard - and turn it on :-)

You can add your instructions in the processor, your peripherals, see the implementation of any instructions in verilog-source ...



An example of the implementation of integer division
module zet_div_uu(clk, ena, z, d, q, s, div0, ovf); // // parameters // parameter z_width = 16; parameter d_width = z_width /2; // // inputs & outputs // input clk; // system clock input ena; // clock enable input [z_width -1:0] z; // divident input [d_width -1:0] d; // divisor output [d_width -1:0] q; // quotient output [d_width -1:0] s; // remainder output div0; output ovf; reg [d_width-1:0] q; reg [d_width-1:0] s; reg div0; reg ovf; // // functions // function [z_width:0] gen_s; input [z_width:0] si; input [z_width:0] di; begin if(si[z_width]) gen_s = {si[z_width-1:0], 1'b0} + di; else gen_s = {si[z_width-1:0], 1'b0} - di; end endfunction function [d_width-1:0] gen_q; input [d_width-1:0] qi; input [z_width:0] si; begin gen_q = {qi[d_width-2:0], ~si[z_width]}; end endfunction function [d_width-1:0] assign_s; input [z_width:0] si; input [z_width:0] di; reg [z_width:0] tmp; begin if(si[z_width]) tmp = si + di; else tmp = si; assign_s = tmp[z_width-1:z_width-d_width]; end endfunction // // variables // reg [d_width-1:0] q_pipe [d_width-1:0]; reg [z_width:0] s_pipe [d_width:0]; reg [z_width:0] d_pipe [d_width:0]; reg [d_width:0] div0_pipe, ovf_pipe; // // perform parameter checks // // synopsys translate_off initial begin if(d_width !== z_width / 2) $display("div.v parameter error (d_width != z_width/2)."); end // synopsys translate_on integer n0, n1, n2, n3; // generate divisor (d) pipe always @(d) d_pipe[0] <= {1'b0, d, {(z_width-d_width){1'b0}} }; always @(posedge clk) if(ena) for(n0=1; n0 <= d_width; n0=n0+1) d_pipe[n0] <= d_pipe[n0-1]; // generate internal remainder pipe always @(z) s_pipe[0] <= z; always @(posedge clk) if(ena) for(n1=1; n1 <= d_width; n1=n1+1) s_pipe[n1] <= gen_s(s_pipe[n1-1], d_pipe[n1-1]); // generate quotient pipe always @(posedge clk) q_pipe[0] <= 0; always @(posedge clk) if(ena) for(n2=1; n2 < d_width; n2=n2+1) q_pipe[n2] <= gen_q(q_pipe[n2-1], s_pipe[n2]); // flags (divide_by_zero, overflow) always @(z or d) begin ovf_pipe[0] <= !(z[z_width-1:d_width] < d); div0_pipe[0] <= ~|d; end always @(posedge clk) if(ena) for(n3=1; n3 <= d_width; n3=n3+1) begin ovf_pipe[n3] <= ovf_pipe[n3-1]; div0_pipe[n3] <= div0_pipe[n3-1]; end // assign outputs always @(posedge clk) if(ena) ovf <= ovf_pipe[d_width]; always @(posedge clk) if(ena) div0 <= div0_pipe[d_width]; always @(posedge clk) if(ena) q <= gen_q(q_pipe[d_width-1], s_pipe[d_width]); always @(posedge clk) if(ena) s <= assign_s(s_pipe[d_width], d_pipe[d_width]); endmodule 




Go to testing



I apologize in advance for the screen copies:

















Next - programming. The compilation and execution speed brings nostalgia ...









Conclusion

I hope the article made you believe in the power of the FPGA and continue learning Verilog.

And someone may now have a dream to make their PC-shku with blackjack :-)



Questions / comments?

Source: https://habr.com/ru/post/146160/



All Articles