Added the OUT instruction to be able to properly address I/O and moved printing logic to a device on the I/O space. Also added IRET which is basically just a RET in this case

This commit is contained in:
(Tim) Efthimis Kritikos 2023-03-09 06:02:41 +00:00
parent 9de83fd7c1
commit 11624ca2d2
11 changed files with 184 additions and 72 deletions

View File

@ -23,9 +23,6 @@ GTKWSAVE=./gtkwave_savefile.gtkw
MICROCODE=system/ucode.txt
BOOTABLES=boot_code/brainfuck_compiled.txt boot_code/brainfuck_interpreted.txt ${BOOT_CODE}
shim:
@echo The processor\'s output handling is being rewritten so the usual mandelbrot program isn\'t working. please git checkout d93c92c00572d812c76d1b42969741d8cfce8d4d
NO_ASM=1
include common.mk

View File

@ -1,8 +1,20 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
org 0x100
INCLUDE brainfuck_compiler_v1.asm
prog:
INCLUDE hello_9086.bf.asm
PRINT_INT_HANDLE:
push AX
MOV AL,DL
out byte #0xA5
POP AX
iret
output_program:
.ORG 0xFFF0

View File

@ -1,6 +1,21 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
ORG 0x100
mov sp,#STACK
INCLUDE brainfuck_interpreter_v0.asm
PRINT_INT_HANDLE:
push AX
MOV AL,DL
out byte #0xA5
POP AX
iret
.BLKB 200
STACK:
prog:
INCLUDE hello_9086.bf.asm

View File

@ -1,6 +1,17 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
ORG 0x100
INCLUDE brainfuck_compiler_v1.asm
PRINT_INT_HANDLE:
push AX
MOV AL,DL
out byte #0xA5
POP AX
iret
prog:
INCLUDE mandelbrot.bf.asm

View File

@ -1,15 +1,15 @@
[*]
[*] GTKWave Analyzer v3.3.111 (w)1999-2020 BSI
[*] Sat Mar 4 23:56:38 2023
[*] Thu Mar 9 04:20:33 2023
[*]
[dumpfile] "/home/user/9086/boot_code/brainfuck_compiled.fst"
[dumpfile_mtime] "Sat Mar 4 23:55:57 2023"
[dumpfile_size] 464968
[dumpfile] "/home/user/9086/system/boot_code.fst"
[dumpfile_mtime] "Thu Mar 9 04:18:18 2023"
[dumpfile_size] 8510
[savefile] "/home/user/9086/gtkwave_savefile.gtkw"
[timestart] 500000000
[size] 1332 1017
[timestart] 198700000000
[size] 1236 1017
[pos] -1 -1
*-37.895050 40500000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
*-34.595051 280500000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TOP.
[treeopen] TOP.system.
[sst_width] 221
@ -21,7 +21,7 @@ TOP.system.clock
TOP.system.reset
TOP.system.p.state[5:0]
@22
TOP.system.p.ucode_seq_addr[3:0]
TOP.system.p.ucode_seq_addr[4:0]
TOP.system.address_bus[19:0]
TOP.system.data_bus[15:0]
TOP.system.p.CIR[15:0]
@ -30,13 +30,14 @@ TOP.system.p.PARAM2[15:0]
@28
TOP.system.p.read
TOP.system.p.write
@29
TOP.system.IOMEM
@22
TOP.system.p.ALU_1A[15:0]
TOP.system.p.ALU_1B[15:0]
TOP.system.p.ALU_1O[15:0]
@28
TOP.system.p.ERROR
@29
TOP.system.p.HALT
[pattern_trace] 1
[pattern_trace] 0

View File

@ -41,6 +41,7 @@ always @ ( * ) begin
`ALU_OP_SHIFT_LEFT: begin C_FLAG=(A&16'h8000)==16'h8000;OUT=A<<B; end
endcase
end else begin
OUT[15:8]=8'b0;
case (op)
`ALU_OP_ADD: {C_FLAG,OUT[7:0]}=A[7:0]+B[7:0];
`ALU_OP_ADD_SIGNED_B: {C_FLAG,OUT[7:0]}=A[7:0]+SIGNED_8B;

View File

@ -1,6 +1,6 @@
.ORG 0x84 /* INT 21 */
DW 0xFFFF /*Code Segment*/
DW 0x014c /*Program Counter*/
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
.ORG 0x0100
start:
@ -40,6 +40,13 @@ TEST_:
ADD AX,#0xDEAD
RET
PRINT_INT_HANDLE:
push AX
MOV AL,DL
out byte #0xA5
POP AX
iret
.BLKB 10
STACK:

View File

@ -52,6 +52,7 @@ module decoder(
,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input
,output reg [2:0]instruction_size
,output reg memio_address_select
,output reg MEM_OR_IO
);
// verilator lint_on UNUSEDSIGNAL
@ -107,6 +108,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b01;
OUT_MOD=3'b011;
MEM_OR_IO=0;
reg_read_port2_addr={Wbit,3'b000};
reg_write_addr={Wbit,3'b000};
ALU_1OP=`ALU_OP_ADD;
@ -137,6 +139,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel2=2'b00;
end
OUT_MOD=IN_MOD;
MEM_OR_IO=0;
memio_address_select=0;
case({Sbit,Wbit})
2'b00,2'b11:begin
@ -182,6 +185,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
endcase
in_alu1_sel1=2'b00;
OUT_MOD=3'b100;
MEM_OR_IO=0;
ALU_1OP=`ALU_OP_SUB;
memio_address_select=0;
if(IN_MOD==3'b011)begin
@ -193,7 +197,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
/*compare register indirect access
* with param */
in_alu1_sel2=2'b00;
next_state=`PROC_DE_LOAD_16_PARAM; /*will the call MEMIO_READ*/
next_state=`PROC_DE_LOAD_16_PARAM; /*will then call MEMIO_READ*/
end
`normal_instruction;
end
@ -207,6 +211,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b00;
OUT_MOD=3'b011;
MEM_OR_IO=0;
reg_write_addr={1'b0,CIR[10:8]};
PARAM1[7:0]=CIR[7:0];
PARAM2=0;
@ -224,6 +229,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b00;
OUT_MOD=3'b011;
MEM_OR_IO=0;
reg_write_addr={1'b1,CIR[10:8]};
ALU_1OP=`ALU_OP_ADD;
PARAM2=0;
@ -240,6 +246,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=CIR[8:8];
in_alu1_sel1=2'b00;
PARAM1=0;
MEM_OR_IO=0;
if(CIR[9:9] == 1)begin
/* Mem/Reg to reg */
IN_MOD={1'b0,CIR[7:6]};
@ -287,6 +294,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel1=2'b01;
in_alu1_sel2=2'b00;
OUT_MOD=3'b011;
MEM_OR_IO=0;
IN_MOD=3'b011;
PARAM2=1;
reg_read_port1_addr={1'b1,CIR[10:8]};
@ -313,6 +321,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel1=2'b00;/* number 1 */
PARAM1=1;
OUT_MOD=IN_MOD;
MEM_OR_IO=0;
/*in case IN_MOD=011 */
reg_read_port2_addr={1'b0,RM};
@ -334,6 +343,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
IN_MOD=3'b011;
HALT<=1;
ERROR<=0;
MEM_OR_IO=0;
seq_addr_entry<=`UCODE_NO_INSTRUCTION;
next_state=`PROC_HALT_STATE;
memio_address_select=0;
@ -357,6 +367,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
reg_read_port2_addr={Wbit,3'b000};
OUT_MOD=3'b100;
ALU_1OP=`ALU_OP_SUB;
MEM_OR_IO=0;
if(Wbit==1)
next_state=`PROC_DE_LOAD_16_PARAM;
else begin
@ -382,6 +393,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu1_sel2=2'b00;
PARAM2={{8{CIR[7:7]}},CIR[7:0]};
ALU_1OP=`ALU_OP_ADD_SIGNED_B;
MEM_OR_IO=0;
OUT_MOD=3'b101;
case(CIR[11:9])
3'b000: begin
@ -431,6 +443,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
PARAM2={{8{CIR[7:7]}},CIR[7:0]};
ALU_1OP=`ALU_OP_ADD_SIGNED_B;
OUT_MOD=3'b101;
MEM_OR_IO=0;
next_state=`PROC_EX_STATE_ENTRY;
`normal_instruction;
memio_address_select=0;
@ -492,6 +505,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=CIR[8:8];
IN_MOD={1'b0,CIR[7:6]};
RM={CIR[2:0]};
MEM_OR_IO=0;
if(Wbit==1)begin
instruction_size=4;
next_state=`PROC_DE_LOAD_16_PARAM;
@ -534,6 +548,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=1;
IN_MOD={1'b0,CIR[7:6]};
RM=CIR[2:0];
MEM_OR_IO=0;
in_alu1_sel1=2'b11;
if (IN_MOD==3'b011)begin
in_alu1_sel2=2'b01;
@ -555,6 +570,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=1;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b11;
MEM_OR_IO=0;
if(Wbit==1)begin
instruction_size=4;
next_state=`PROC_DE_LOAD_16_PARAM;
@ -576,8 +592,8 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
// [skiped] 2) clear trap and interrupt enable flag
// [skiped] 3) push CS
// [skiped] 4) fetch CS from interrupt table
// 5) push ProgCount
// 6) fetch ProgCount from interrupt table
// 5) push ProgCount
// 6) fetch ProgCount from interrupt table
instruction_size=2;
opcode_size=0;
Wbit=1;
@ -585,13 +601,35 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
PARAM2=2;
seq_addr_entry<=`UCODE_INT_ENTRY;
memio_address_select=0;
///* Emulate MS-DOS print routines */
//if(CIR[7:0]==8'h21 && register_file.registers[0][15:8]==8'h02)begin
// $write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/
//end
//next_state=`PROC_IF_STATE_ENTRY;
//`normal_instruction;
//memio_address_select=0;
end
11'b1110_011?_???:begin
/* OUT - write AL or AX to a defined output port */
/* | 1 1 1 0 0 1 1 W | DATA 8 | */
memio_address_select=1;
Wbit=CIR[8:8];
opcode_size=0;
instruction_size=2;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b11;
reg_read_port1_addr={Wbit,3'b000};
next_state=`PROC_DE_LOAD_8_PARAM;
MEM_OR_IO=1;
PARAM1=0;
OUT_MOD={3'b000};
IN_MOD=3'b011;
end
11'b1100_1111_???:begin
/* IRET - Return from interrupt */
/* | 1 1 0 0 1 1 1 1 | */
// Sicne we only push one thing on the stack
// on INT we can just reuse the code from RET
instruction_size=1;
opcode_size=0;
Wbit=1;
Sbit=0;
PARAM1=2;
seq_addr_entry<=`UCODE_RET_ENTRY;
memio_address_select=0;
end
default:begin
`invalid_instruction
@ -636,6 +674,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
if(ucode_data[38:38]==1)
Wbit=ucode_data[37:37];
memio_address_select=ucode_data[39:39];
MEM_OR_IO=0;
end
end
`undef invalid_instruction

View File

@ -30,7 +30,7 @@ initial begin
$display("No boot code specified. Please add +BOOT_CODE=<path> to your vvp args");
$finish;
end
$readmemh(boot_code, memory,0,16383);
$readmemh(boot_code, memory,0,32767);
end
assign data[7:0] = !address[0:0] & !rd & !cs ? memory[address[16:1]][15:8] : 8'hz;

View File

@ -58,6 +58,7 @@ reg instruction_size_init;
wire [2:0] instruction_size;
assign instruction_size = instruction_size_init ? 3'b010 : DE_instruction_size;
wire memio_address_select;
wire MEM_OR_IO;
decoder decoder(
.CIR(CIR),
@ -78,7 +79,8 @@ decoder decoder(
.SIMPLE_MICRO(SIMPLE_MICRO),
.seq_addr_input(ucode_seq_addr),
.instruction_size(DE_instruction_size),
.memio_address_select(memio_address_select)
.memio_address_select(memio_address_select),
.MEM_OR_IO(MEM_OR_IO)
);
assign Wbit=INSTRUCTION_INFO[2:2];
@ -199,7 +201,6 @@ always @(posedge clock) begin
ProgCount <= 'hFFF0;//TODO: Implement Segmentation and set to zero
HALT <= 0;
ERROR <= 0;
IOMEM <= 0;
SIMPLE_MICRO <= 0;
reg_write_we <= 1;
instruction_size_init <= 1;
@ -222,6 +223,7 @@ always @(posedge clock) begin
`endif
BHE <= 0;
external_address_bus <= {4'b0,ProgCount};
IOMEM <= 0;
read <= 0;
write <= 1;
reg_write_we <= 1;
@ -444,7 +446,7 @@ always @(posedge clock) begin
external_address_bus <= {4'b0,reg_read_port1_data[15:0]};
else
external_address_bus <= {4'b0,ALU_1O};
state <= reg_read_port1_data[0:0]?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA;
state <= (memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA;
end
`PROC_MEMIO_GET_ALIGNED_DATA:begin
PARAM2 <= (Wbit==1)? external_data_bus : {8'b0,external_data_bus[7:0]} ;
@ -473,43 +475,46 @@ always @(posedge clock) begin
3'b000,
3'b001,
3'b010 : begin
case (RM) /* Duplicate code with write... */
3'b000:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b001:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b010:begin
/*[BP]+[SI]*/
`invalid_instruction
end
3'b011:begin
/*[BP]+[DI]*/
`invalid_instruction
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
state <= `PROC_MEMIO_WRITE;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
state <= `PROC_MEMIO_WRITE;
end
3'b110:begin
/*d16 */
`invalid_instruction
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
state <= `PROC_MEMIO_WRITE;
end
endcase
if(memio_address_select==1)
state <= `PROC_MEMIO_WRITE;
else
case (RM) /* Duplicate code with write... */
3'b000:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b001:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b010:begin
/*[BP]+[SI]*/
`invalid_instruction
end
3'b011:begin
/*[BP]+[DI]*/
`invalid_instruction
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
state <= `PROC_MEMIO_WRITE;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
state <= `PROC_MEMIO_WRITE;
end
3'b110:begin
/*d16 */
`invalid_instruction
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
state <= `PROC_MEMIO_WRITE;
end
endcase
end
3'b011:begin
reg_write_we <= 0;
@ -549,17 +554,26 @@ always @(posedge clock) begin
endcase
end
`PROC_MEMIO_WRITE:begin
/* ADDRESS: reg_read_port1_data DATA:ALU1_O */
/* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */
/* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */
`ifdef DEBUG_MEMORY_WRITES
$display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O);
`endif
external_address_bus <= {4'b0,reg_read_port1_data[15:0]};
if(memio_address_select==0)
external_address_bus <= {4'b0,reg_read_port1_data[15:0]};
else
external_address_bus <= {4'b0,ALU_1O};
IOMEM <= MEM_OR_IO;
state <= (Wbit==0) ? `PROC_MEMIO_PUT_BYTE : (reg_read_port1_data[0:0]?`PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:`PROC_MEMIO_PUT_ALIGNED_16BIT_DATA) ;
end
`PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:begin
read <= 1;
BHE <= 0;
data_bus_output_register <= {ALU_1O[7:0],ALU_1O[15:8]};
if(memio_address_select==0)
data_bus_output_register <= {ALU_1O[7:0],ALU_1O[15:8]};
else
data_bus_output_register <= {reg_read_port1_data[7:0],reg_read_port1_data[15:8]};
state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT;
end
`PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT:begin
@ -580,11 +594,18 @@ always @(posedge clock) begin
`PROC_MEMIO_PUT_BYTE:begin
read <= 1;
state <= `PROC_MEMIO_WRITE_EXIT;
if(reg_read_port1_data[0:0]==0) begin
if((memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])==0) begin
BHE <= 1;
data_bus_output_register <= {8'b0,ALU_1O[7:0]};
if(memio_address_select==0)
data_bus_output_register <= {8'b0,ALU_1O[7:0]};
else
data_bus_output_register <= {8'b0,reg_read_port1_data[7:0]};
end else begin
data_bus_output_register <= {ALU_1O[7:0],8'b0};
BHE <= 0;
if(memio_address_select==0)
data_bus_output_register <= {ALU_1O[7:0],8'b0};
else
data_bus_output_register <= {reg_read_port1_data[7:0],8'b0};
end
end
`PROC_MEMIO_WRITE_EXIT:begin

View File

@ -14,6 +14,14 @@ initial begin
end
end
always @(negedge wr) begin
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )
$write("%s" ,data_bus[15:8]);
//if(CIR[7:0]==8'h21 && register_file.registers[0][15:8]==8'h02)begin
// $write("%s" ,register_file.registers[2][7:0]);
//end
end
reg [1:0] finish;
string memdump_name;