summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-10-09 19:25:27 -0600
committerAlejandro Soto <alejandro@34project.org>2022-10-09 19:25:27 -0600
commit7d95ff01bcd8c42efe118fd1bddaabfca0e937eb (patch)
tree1d61430989192de9f34fb327772ceff7cac5c71a
parent1f1f61bbab1396278a861e46fd65a50d1914585e (diff)
Implement most memory transactions
Diffstat (limited to '')
-rw-r--r--rtl/core/arm810.sv20
-rw-r--r--rtl/core/cycles.sv130
-rw-r--r--rtl/core/cycles/ldst/pop.sv56
-rw-r--r--rtl/core/decode/decode.sv52
-rw-r--r--rtl/core/decode/ldst/addr.sv14
-rw-r--r--rtl/core/decode/ldst/misc.sv13
-rw-r--r--rtl/core/decode/ldst/multiple.sv10
-rw-r--r--rtl/core/decode/ldst/single.sv4
-rw-r--r--rtl/core/isa.sv3
-rw-r--r--rtl/core/uarch.sv3
10 files changed, 261 insertions, 44 deletions
diff --git a/rtl/core/arm810.sv b/rtl/core/arm810.sv
index d3b2c6f..975ce03 100644
--- a/rtl/core/arm810.sv
+++ b/rtl/core/arm810.sv
@@ -33,6 +33,7 @@ module arm810
ptr dec_branch_offset;
snd_decode dec_snd;
data_decode dec_data;
+ ldst_decode dec_ldst;
core_decode decode
(
@@ -44,6 +45,7 @@ module arm810
.branch_offset(dec_branch_offset),
.snd_ctrl(dec_snd),
.data_ctrl(dec_data),
+ .ldst_ctrl(dec_ldst),
.*
);
@@ -53,7 +55,7 @@ module arm810
psr_mode reg_mode;
alu_op alu_ctrl;
shifter_control shifter_ctrl;
- word alu_b, wr_value;
+ word alu_a, alu_b, wr_value;
logic[7:0] shifter_shift;
core_cycles cycles
@@ -61,6 +63,12 @@ module arm810
.branch(explicit_branch),
.alu(alu_ctrl),
.shifter(shifter_ctrl),
+ .mem_addr(data_addr),
+ .mem_start(data_start),
+ .mem_write(data_write),
+ .mem_ready(data_ready),
+ .mem_data_rd(data_data_rd),
+ .mem_data_wr(data_data_wr),
.*
);
@@ -93,7 +101,7 @@ module arm810
core_alu #(.W(32)) alu
(
.op(alu_ctrl),
- .a(rd_value_a),
+ .a(alu_a),
.b(alu_b),
.q(q_alu),
.nzcv(alu_flags),
@@ -114,13 +122,9 @@ module arm810
.c(c_shifter)
);
- //TODO
ptr data_addr;
- logic data_start, data_write, data_ready;
- word data_data_rd, data_data_wr;
-
- logic insn_ready;
- word insn_data_rd;
+ logic data_start, data_write, data_ready, insn_ready;
+ word data_data_rd, data_data_wr, insn_data_rd;
core_mmu mmu
(
diff --git a/rtl/core/cycles.sv b/rtl/core/cycles.sv
index ddaf237..c416187 100644
--- a/rtl/core/cycles.sv
+++ b/rtl/core/cycles.sv
@@ -10,12 +10,16 @@ module core_cycles
input ptr dec_branch_offset,
input snd_decode dec_snd,
input data_decode dec_data,
+ input ldst_decode dec_ldst,
input ptr fetch_insn_pc,
input psr_flags flags,
- input word rd_value_b,
+ input word rd_value_a,
+ rd_value_b,
q_alu,
q_shifter,
input logic c_shifter,
+ mem_ready,
+ input word mem_data_rd,
output logic stall,
branch,
@@ -29,31 +33,53 @@ module core_cycles
pc_visible,
output psr_mode reg_mode,
output alu_op alu,
- output word alu_b,
+ output word alu_a,
+ alu_b,
wr_value,
output shifter_control shifter,
- output logic[7:0] shifter_shift
+ output logic[7:0] shifter_shift,
+ output ptr mem_addr,
+ output word mem_data_wr,
+ output logic mem_start,
+ mem_write
);
enum
{
ISSUE,
RD_INDIRECT_SHIFT,
- WITH_SHIFT
+ WITH_SHIFT,
+ TRANSFER,
+ BASE_WRITEBACK
} cycle, next_cycle;
logic bubble, final_writeback, final_update_flags,
+ ldst, ldst_pre, ldst_increment, ldst_writeback, pop_valid,
data_snd_is_imm, data_snd_shift_by_reg, trivial_shift;
logic[5:0] data_shift_imm;
logic[11:0] data_imm;
- word saved_base;
- reg_num r_shift, final_rd;
+ word saved_base, mem_offset;
+ reg_num r_shift, final_rd, popped_upper, popped_lower, popped;
+ reg_list mem_regs, next_regs_upper, next_regs_lower;
ptr pc;
assign stall = (next_cycle != ISSUE) | bubble;
assign pc_visible = pc + 2;
assign reg_mode = `MODE_SVC; //TODO
+ assign trivial_shift = shifter_shift == 0;
+ assign mem_data_wr = rd_value_b;
+ assign popped = ldst_increment ? popped_lower : popped_upper;
+
+ core_cycles_ldst_pop ldst_pop
+ (
+ .regs(mem_regs),
+ .valid(pop_valid),
+ .next_upper(next_regs_upper),
+ .next_lower(next_regs_lower),
+ .pop_upper(popped_upper),
+ .pop_lower(popped_lower)
+ );
always_comb begin
unique case(cycle)
@@ -61,10 +87,6 @@ module core_cycles
default: shifter_shift = {2'b00, data_shift_imm};
endcase
- trivial_shift = 1;
- if(final_writeback & (shifter.shl | shifter.shr | shifter.ror))
- trivial_shift = shifter_shift == 0;
-
next_cycle = ISSUE;
unique case(cycle)
@@ -78,34 +100,54 @@ module core_cycles
if(~trivial_shift)
next_cycle = WITH_SHIFT;
+ TRANSFER:
+ if(!mem_ready || pop_valid)
+ next_cycle = TRANSFER;
+ else if(ldst_writeback)
+ next_cycle = BASE_WRITEBACK;
+
default: ;
endcase
if(bubble)
next_cycle = ISSUE;
+ else if(next_cycle == ISSUE && ldst)
+ next_cycle = TRANSFER;
unique case(cycle)
- ISSUE:
+ TRANSFER: alu_a = saved_base;
+ default: alu_a = rd_value_a;
+ endcase
+
+ unique case(cycle)
+ RD_INDIRECT_SHIFT, WITH_SHIFT:
+ alu_b = saved_base;
+
+ TRANSFER:
+ alu_b = mem_offset;
+
+ default:
if(data_snd_is_imm)
alu_b = {{20{1'b0}}, data_imm};
else
alu_b = rd_value_b;
-
- RD_INDIRECT_SHIFT, WITH_SHIFT:
- alu_b = saved_base;
endcase
end
always_ff @(posedge clk) begin
cycle <= next_cycle;
bubble <= 0;
+ branch <= 0;
writeback <= 0;
- wr_value <= q_alu;
+
+ unique case(cycle)
+ TRANSFER: wr_value <= mem_data_rd;
+ BASE_WRITEBACK: wr_value <= saved_base;
+ default: wr_value <= q_alu;
+ endcase
unique case(next_cycle)
ISSUE: begin
- branch <= 0;
- branch_target <= {30{1'bx}};
final_writeback <= 0;
final_update_flags <= 0;
@@ -135,6 +177,16 @@ module core_cycles
r_shift <= dec_snd.r_shift;
c_in <= flags.c;
+ // TODO: dec_ldst.unprivileged/user_regs
+ // TODO: byte/halfword sizes
+ ldst <= dec_ldst.enable;
+ ldst_pre <= dec_ldst.pre_indexed;
+ ldst_increment <= dec_ldst.increment;
+ ldst_writeback <= dec_ldst.writeback;
+
+ mem_regs <= dec_ldst.regs;
+ mem_write <= !dec_ldst.load;
+
final_rd <= dec_data.rd;
final_writeback <= dec_writeback;
final_update_flags <= dec_update_flags;
@@ -156,6 +208,39 @@ module core_cycles
c_in <= c_shifter;
saved_base <= q_shifter;
end
+
+ TRANSFER: begin
+ if(cycle != TRANSFER) begin
+ ldst <= 0;
+ mem_offset <= alu_b;
+ end
+
+ if(mem_ready) begin
+ wr_value <= mem_data_rd;
+ writeback <= !mem_write;
+ end
+
+ if(cycle != TRANSFER || mem_ready) begin
+ mem_regs <= ldst_increment ? next_regs_lower : next_regs_upper;
+ mem_addr <= ldst_pre ? q_alu[31:2] : alu_a[31:2];
+ saved_base <= q_alu;
+
+ if(pop_valid) begin
+ rd <= popped;
+ rb <= popped;
+ end else
+ rb <= final_rd; // Viene de dec_ldst.rd
+ end
+
+ mem_start <= cycle != TRANSFER || (mem_ready && pop_valid);
+ end
+
+ BASE_WRITEBACK: begin
+ rd <= final_rd;
+ wr_value <= mem_data_rd;
+ writeback <= !mem_write;
+ final_rd <= ra;
+ end
endcase
end
@@ -170,6 +255,17 @@ module core_cycles
branch_target = 30'd0;
data_snd_shift_by_reg = 0;
+ ldst = 0;
+ ldst_pre = 0;
+ ldst_writeback = 0;
+ ldst_increment = 0;
+
+ mem_addr = 30'b0;
+ mem_write = 0;
+ mem_start = 0;
+ mem_regs = 16'b0;
+ mem_offset = 0;
+
final_rd = 0;
final_writeback = 0;
end
diff --git a/rtl/core/cycles/ldst/pop.sv b/rtl/core/cycles/ldst/pop.sv
new file mode 100644
index 0000000..a4078d1
--- /dev/null
+++ b/rtl/core/cycles/ldst/pop.sv
@@ -0,0 +1,56 @@
+`include "core/uarch.sv"
+
+module core_cycles_ldst_pop
+(
+ input reg_list regs,
+
+ output logic valid,
+ output reg_list next_upper,
+ next_lower,
+ output reg_num pop_upper,
+ pop_lower
+);
+
+ assign valid = regs != 16'b0;
+
+ always_comb begin
+ unique casez(regs)
+ 16'b???????????????1: begin pop_lower = 4'h0; next_lower = {regs[15:1], 1'b0}; end
+ 16'b??????????????10: begin pop_lower = 4'h1; next_lower = {regs[15:2], 2'b0}; end
+ 16'b?????????????100: begin pop_lower = 4'h2; next_lower = {regs[15:3], 3'b0}; end
+ 16'b????????????1000: begin pop_lower = 4'h3; next_lower = {regs[15:4], 4'b0}; end
+ 16'b???????????10000: begin pop_lower = 4'h4; next_lower = {regs[15:5], 5'b0}; end
+ 16'b??????????100000: begin pop_lower = 4'h5; next_lower = {regs[15:6], 6'b0}; end
+ 16'b?????????1000000: begin pop_lower = 4'h6; next_lower = {regs[15:7], 7'b0}; end
+ 16'b????????10000000: begin pop_lower = 4'h7; next_lower = {regs[15:8], 8'b0}; end
+ 16'b???????100000000: begin pop_lower = 4'h8; next_lower = {regs[15:9], 9'b0}; end
+ 16'b??????1000000000: begin pop_lower = 4'h9; next_lower = {regs[15:10], 10'b0}; end
+ 16'b?????10000000000: begin pop_lower = 4'ha; next_lower = {regs[15:11], 11'b0}; end
+ 16'b????100000000000: begin pop_lower = 4'hb; next_lower = {regs[15:12], 12'b0}; end
+ 16'b???1000000000000: begin pop_lower = 4'hc; next_lower = {regs[15:13], 13'b0}; end
+ 16'b??10000000000000: begin pop_lower = 4'hd; next_lower = {regs[15:14], 14'b0}; end
+ 16'b?100000000000000: begin pop_lower = 4'he; next_lower = {regs[15], 15'b0}; end
+ default: begin pop_lower = 4'hf; next_lower = 16'b0; end
+ endcase
+
+ unique casez(regs)
+ 16'b1???????????????: begin pop_upper = 4'hf; next_upper = { 1'b0, regs[14:0]}; end
+ 16'b01??????????????: begin pop_upper = 4'he; next_upper = { 2'b0, regs[13:0]}; end
+ 16'b001?????????????: begin pop_upper = 4'hd; next_upper = { 3'b0, regs[12:0]}; end
+ 16'b0001????????????: begin pop_upper = 4'hc; next_upper = { 4'b0, regs[11:0]}; end
+ 16'b00001???????????: begin pop_upper = 4'hb; next_upper = { 5'b0, regs[10:0]}; end
+ 16'b000001??????????: begin pop_upper = 4'ha; next_upper = { 6'b0, regs[9:0]}; end
+ 16'b0000001?????????: begin pop_upper = 4'h9; next_upper = { 7'b0, regs[8:0]}; end
+ 16'b00000001????????: begin pop_upper = 4'h8; next_upper = { 8'b0, regs[7:0]}; end
+ 16'b000000001???????: begin pop_upper = 4'h7; next_upper = { 9'b0, regs[6:0]}; end
+ 16'b0000000001??????: begin pop_upper = 4'h6; next_upper = {10'b0, regs[5:0]}; end
+ 16'b00000000001?????: begin pop_upper = 4'h5; next_upper = {11'b0, regs[4:0]}; end
+ 16'b000000000001????: begin pop_upper = 4'h4; next_upper = {12'b0, regs[3:0]}; end
+ 16'b0000000000001???: begin pop_upper = 4'h3; next_upper = {13'b0, regs[2:0]}; end
+ 16'b00000000000001??: begin pop_upper = 4'h2; next_upper = {14'b0, regs[1:0]}; end
+ 16'b000000000000001?: begin pop_upper = 4'h1; next_upper = {15'b0, regs[0]}; end
+ default: begin pop_upper = 4'h0; next_upper = 16'b0; end
+ endcase
+ end
+
+endmodule
diff --git a/rtl/core/decode/decode.sv b/rtl/core/decode/decode.sv
index d14841b..16b53d4 100644
--- a/rtl/core/decode/decode.sv
+++ b/rtl/core/decode/decode.sv
@@ -13,12 +13,12 @@ module core_decode
branch,
output ptr branch_offset,
output snd_decode snd_ctrl,
- output data_decode data_ctrl
+ output data_decode data_ctrl,
+ output ldst_decode ldst_ctrl
);
//TODO
logic restore_spsr;
- ldst_decode ldst_ctrl;
logic cond_undefined;
@@ -77,10 +77,16 @@ module core_decode
);
ldst_decode ldst_misc;
+ logic ldst_misc_off_is_reg;
+ reg_num ldst_misc_off_reg;
+ logic[7:0] ldst_misc_off_imm;
core_decode_ldst_misc group_ldst_misc
(
.decode(ldst_misc),
+ .off_imm(ldst_misc_off_imm),
+ .off_reg(ldst_misc_off_reg),
+ .off_is_reg(ldst_misc_off_is_reg),
.*
);
@@ -94,6 +100,15 @@ module core_decode
.*
);
+ ldst_decode ldst_addr;
+ data_decode data_ldst;
+
+ core_decode_ldst_addr ldst2data
+ (
+ .ldst(ldst_addr),
+ .alu(data_ldst)
+ );
+
always_comb begin
undefined = cond_undefined;
@@ -102,10 +117,14 @@ module core_decode
update_flags = 0;
data_ctrl = {($bits(data_ctrl)){1'bx}};
- snd_ctrl = {($bits(snd_ctrl)){1'bx}};
- snd_ctrl.shl = 0;
+ snd_ctrl = {$bits(snd_ctrl){1'bx}};
+ snd_ctrl.shl = 1;
snd_ctrl.shr = 0;
snd_ctrl.ror = 0;
+ snd_ctrl.is_imm = 1;
+ snd_ctrl.shift_imm = {$bits(snd_ctrl.shift_imm){1'b0}};
+ snd_ctrl.shift_by_reg = 0;
+
snd_is_imm = 1'bx;
snd_ror_if_imm = 1'bx;
snd_shift_by_reg_if_reg = 1'bx;
@@ -148,7 +167,7 @@ module core_decode
snd_ctrl = snd;
ldst_ctrl = ldst_single;
- ldst_ctrl.enable = 1;
+ ldst_addr = ldst_single;
undefined = undefined | snd_undefined;
end
@@ -157,15 +176,22 @@ module core_decode
priority casez(insn `FIELD_OP)
`INSN_LDRB, `INSN_LDRSB, `INSN_LDRSH, `INSN_STRH: begin
ldst_ctrl = ldst_misc;
- ldst_ctrl.enable = 1;
+ ldst_addr = ldst_misc;
+
+ snd_ctrl.r = ldst_misc_off_reg;
+ snd_ctrl.imm = {4'b0, ldst_misc_off_imm};
+ snd_ctrl.is_imm = !ldst_misc_off_is_reg;
end
- default: undefined = 1;
+ default:
+ undefined = 1;
endcase
`GROUP_LDST_MULT: begin
ldst_ctrl = ldst_multiple;
- ldst_ctrl.enable = 1;
+ ldst_addr = ldst_multiple;
+ snd_ctrl.imm = 12'd4;
+
restore_spsr = ldst_mult_restore_spsr;
end
@@ -178,6 +204,16 @@ module core_decode
default: undefined = 1;
endcase
+ unique casez(insn `FIELD_OP)
+ `GROUP_LDST_SINGLE, `GROUP_LDST_MISC, `GROUP_LDST_MULT: begin
+ ldst_ctrl.enable = 1;
+ data_ctrl = data_ldst;
+ writeback = ldst_ctrl.writeback || ldst_ctrl.load;
+ end
+
+ default: ;
+ endcase
+
if(undefined) begin
branch = 1'bx;
writeback = 1'bx;
diff --git a/rtl/core/decode/ldst/addr.sv b/rtl/core/decode/ldst/addr.sv
new file mode 100644
index 0000000..4a61231
--- /dev/null
+++ b/rtl/core/decode/ldst/addr.sv
@@ -0,0 +1,14 @@
+`include "core/uarch.sv"
+
+module core_decode_ldst_addr
+(
+ input ldst_decode ldst,
+
+ output data_decode alu
+);
+
+ assign alu.op = ldst.increment ? `ALU_ADD : `ALU_SUB;
+ assign alu.rn = ldst.rn;
+ assign alu.rd = ldst.rd;
+
+endmodule
diff --git a/rtl/core/decode/ldst/misc.sv b/rtl/core/decode/ldst/misc.sv
index de2428f..f2fe258 100644
--- a/rtl/core/decode/ldst/misc.sv
+++ b/rtl/core/decode/ldst/misc.sv
@@ -5,7 +5,10 @@ module core_decode_ldst_misc
(
input word insn,
- output ldst_decode decode
+ output ldst_decode decode,
+ output logic off_is_reg,
+ output logic[7:0] off_imm,
+ output reg_num off_reg
);
logic p, w;
@@ -17,10 +20,14 @@ module core_decode_ldst_misc
assign decode.increment = insn `FIELD_LDST_MISC_U;
assign decode.writeback = !p || w;
assign decode.sign_extend = insn `FIELD_LDST_MISC_S;
- assign decode.pre_indexed = p && w;
+ assign decode.pre_indexed = p;
assign decode.unprivileged = 0;
assign decode.user_regs = 0;
- assign decode.reg_list = 16'b0;
+ assign decode.regs = 16'b0;
+
+ assign off_imm = {insn `FIELD_LDST_MISC_IMM_HI, insn `FIELD_LDST_MISC_IMM_LO};
+ assign off_reg = insn `FIELD_LDST_MISC_RM;
+ assign off_is_reg = insn `FIELD_LDST_MISC_REG;
assign p = insn `FIELD_LDST_MISC_P;
assign w = insn `FIELD_LDST_MISC_W;
diff --git a/rtl/core/decode/ldst/multiple.sv b/rtl/core/decode/ldst/multiple.sv
index 24e8e5b..d286a67 100644
--- a/rtl/core/decode/ldst/multiple.sv
+++ b/rtl/core/decode/ldst/multiple.sv
@@ -10,7 +10,7 @@ module core_decode_ldst_multiple
);
logic s, l;
- logic[15:0] reg_list;
+ reg_list regs;
assign decode.rn = insn `FIELD_LDST_MULT_RN;
assign decode.size = LDST_WORD;
@@ -20,13 +20,13 @@ module core_decode_ldst_multiple
assign decode.sign_extend = 0;
assign decode.pre_indexed = insn `FIELD_LDST_MULT_P;
assign decode.unprivileged = 0;
- assign decode.user_regs = s && (!l || !reg_list[`R15]);
- assign decode.reg_list = reg_list;
+ assign decode.user_regs = s && !(l && regs[`R15]);
+ assign decode.regs = regs;
assign s = insn `FIELD_LDST_MULT_S;
assign l = insn `FIELD_LDST_LD;
- assign reg_list = insn `FIELD_LDST_MULT_LIST;
- assign restore_spsr = s && l && reg_list[`R15];
+ assign regs = insn `FIELD_LDST_MULT_LIST;
+ assign restore_spsr = s && l && regs[`R15];
endmodule
diff --git a/rtl/core/decode/ldst/single.sv b/rtl/core/decode/ldst/single.sv
index 5bcb638..0665178 100644
--- a/rtl/core/decode/ldst/single.sv
+++ b/rtl/core/decode/ldst/single.sv
@@ -18,10 +18,10 @@ module core_decode_ldst_single
assign decode.increment = insn `FIELD_LDST_SINGLE_U;
assign decode.writeback = !p || w;
assign decode.sign_extend = 0;
- assign decode.pre_indexed = p && w;
+ assign decode.pre_indexed = p;
assign decode.unprivileged = !p && w;
assign decode.user_regs = 0;
- assign decode.reg_list = 16'b0;
+ assign decode.regs = 16'b0;
assign p = insn `FIELD_LDST_SINGLE_P;
assign w = insn `FIELD_LDST_SINGLE_W;
diff --git a/rtl/core/isa.sv b/rtl/core/isa.sv
index 7298b9a..c98cfd9 100644
--- a/rtl/core/isa.sv
+++ b/rtl/core/isa.sv
@@ -118,8 +118,10 @@
`define INSN_STM_CUR 28'b100_?_?_0_?_0_????_????????????????
`define INSN_STM_USR 28'b100_?_?_1_0_0_????_????????????????
+`define GROUP_LDST_SINGLE 28'b01_?_?_?_?_?_?_????_????_????????????
`define GROUP_LDST_SINGLE_IMM 28'b01_0_?_?_?_?_?_????_????_????????????
`define GROUP_LDST_SINGLE_REG 28'b01_1_?_?_?_?_?_????_????_?????_??_0_????
+`define GROUP_LDST_MISC 28'b000_?_?_?_?_?_????_????_????_1_?_?_1_????
`define GROUP_LDST_MISC_IMM 28'b000_?_?_1_?_?_????_????_????_1_?_?_1_????
`define GROUP_LDST_MISC_REG 28'b000_?_?_0_?_?_????_????_0000_1_?_?_1_????
`define GROUP_LDST_MULT 28'b100_?_?_?_?_?_????_????????????????
@@ -135,6 +137,7 @@
`define FIELD_LDST_MISC_P [24]
`define FIELD_LDST_MISC_U [23]
+`define FIELD_LDST_MISC_REG [22]
`define FIELD_LDST_MISC_W [21]
`define FIELD_LDST_MISC_RN [19:16]
`define FIELD_LDST_MISC_RD [15:12]
diff --git a/rtl/core/uarch.sv b/rtl/core/uarch.sv
index 2cd6f24..bd9ed03 100644
--- a/rtl/core/uarch.sv
+++ b/rtl/core/uarch.sv
@@ -5,6 +5,7 @@
`define NOP 32'd0
typedef logic[3:0] reg_num;
+typedef logic[15:0] reg_list;
typedef logic[31:0] word;
typedef logic[29:0] ptr;
@@ -104,7 +105,7 @@ typedef struct packed
/* P. 482: "If no bits are set, the result is UNPREDICTABLE."
* Esto permite diferenciar entre ldst mĂșltiple y simple.
*/
- logic[15:0] reg_list;
+ reg_list regs;
} ldst_decode;
typedef struct packed